diff --git a/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeProcessor.java b/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeProcessor.java index 244bd9abb..37be9d77b 100644 --- a/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeProcessor.java +++ b/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeProcessor.java @@ -87,20 +87,7 @@ public Type processType() { return type; } - if (type.kind() == Type.Kind.WILDCARD_TYPE) { - type = TypeUtil.resolveWildcard(type.asWildcardType()); - } - - if (type.kind() == Type.Kind.TYPE_VARIABLE || - type.kind() == Type.Kind.UNRESOLVED_TYPE_VARIABLE) { - // Resolve type variable to real variable. - type = resolveTypeVariable(schema, type, false); - } - - if (TypeUtil.isWrappedType(type)) { - // Unwrap and proceed using the wrapped type - type = TypeUtil.unwrapType(type); - } + type = maybeResolveType(type); if (isArrayType(type, annotationTarget)) { return readArrayType(type.asArrayType(), this.schema); @@ -150,6 +137,25 @@ public Type processType() { return type; } + private Type maybeResolveType(Type type) { + if (type.kind() == Type.Kind.WILDCARD_TYPE) { + type = TypeUtil.resolveWildcard(type.asWildcardType()); + } + + if (type.kind() == Type.Kind.TYPE_VARIABLE || + type.kind() == Type.Kind.UNRESOLVED_TYPE_VARIABLE) { + // Resolve type variable to real variable. + type = resolveTypeVariable(schema, type, false); + } + + if (TypeUtil.isWrappedType(type)) { + // Unwrap and proceed using the wrapped type + type = TypeUtil.unwrapType(type); + } + + return type; + } + /** * Only allow registration of a type if the annotation target (field or method) that * refers to the type's class is not annotated with an annotation that alters @@ -313,29 +319,10 @@ private Schema resolveParameterizedType(Type valueType, Schema propsSchema) { typeResolver, propsSchema); } + } else if (isArrayType(valueType, null)) { + readArrayType(valueType.asArrayType(), propsSchema); } else if (index.containsClass(valueType)) { - if (isA(valueType, ENUM_TYPE)) { - DataObjectLogging.logger.processingEnum(type); - propsSchema = SchemaFactory.enumToSchema(context, valueType); - } else { - SchemaSupport.setType(propsSchema, Schema.SchemaType.OBJECT); - } - - SchemaRegistry registry = context.getSchemaRegistry(); - - if (registry.hasSchema(valueType, context.getJsonViews(), typeResolver)) { - if (allowRegistration()) { - propsSchema = registry.lookupRef(valueType, context.getJsonViews()); - } else { - pushToStack(valueType, propsSchema); - } - } else { - pushToStack(valueType, propsSchema); - if (allowRegistration()) { - propsSchema = registry.registerReference(valueType, context.getJsonViews(), typeResolver, - propsSchema); - } - } + propsSchema = resolveIndexedParameterizedType(valueType, propsSchema); } return propsSchema; @@ -357,6 +344,33 @@ private Type resolveTypeVariable(Schema schema, Type fieldType, boolean pushToSt return resolvedType; } + private Schema resolveIndexedParameterizedType(Type valueType, Schema propsSchema) { + if (isA(valueType, ENUM_TYPE)) { + DataObjectLogging.logger.processingEnum(type); + propsSchema = SchemaFactory.enumToSchema(context, valueType); + } else { + SchemaSupport.setType(propsSchema, Schema.SchemaType.OBJECT); + } + + SchemaRegistry registry = context.getSchemaRegistry(); + + if (registry.hasSchema(valueType, context.getJsonViews(), typeResolver)) { + if (allowRegistration()) { + propsSchema = registry.lookupRef(valueType, context.getJsonViews()); + } else { + pushToStack(valueType, propsSchema); + } + } else { + pushToStack(valueType, propsSchema); + if (allowRegistration()) { + propsSchema = registry.registerReference(valueType, context.getJsonViews(), typeResolver, + propsSchema); + } + } + + return propsSchema; + } + private void pushResolvedToStack(Type type, Schema schema) { Type resolvedType = this.typeResolver.resolve(type); pushToStack(resolvedType, schema); diff --git a/core/src/test/java/io/smallrye/openapi/runtime/scanner/StandaloneSchemaScanTest.java b/core/src/test/java/io/smallrye/openapi/runtime/scanner/StandaloneSchemaScanTest.java index 181ce431d..ba8424ba6 100644 --- a/core/src/test/java/io/smallrye/openapi/runtime/scanner/StandaloneSchemaScanTest.java +++ b/core/src/test/java/io/smallrye/openapi/runtime/scanner/StandaloneSchemaScanTest.java @@ -888,4 +888,17 @@ class Bean { assertJsonEquals("components.schemas.primitive-formats.json", Bean.class); } + + @Test + void testMultidimensionalArrayGenericType() throws IOException, JSONException { + @Schema(name = "Bean") + class Bean { + @Schema(description = "Multi-dimensional Array.", examples = "[[[1.23, 1.0903]]]") + List list; + @Schema(description = "Multi-dimensional Array.", examples = "{ \"data\": [[[1.23, 1.0903]]] }") + Map> mapOfLists; + } + + assertJsonEquals("components.schemas.multi-array-generic.json", Bean.class); + } } diff --git a/core/src/test/resources/io/smallrye/openapi/runtime/scanner/components.schemas.multi-array-generic.json b/core/src/test/resources/io/smallrye/openapi/runtime/scanner/components.schemas.multi-array-generic.json new file mode 100644 index 000000000..0d3e73ac1 --- /dev/null +++ b/core/src/test/resources/io/smallrye/openapi/runtime/scanner/components.schemas.multi-array-generic.json @@ -0,0 +1,47 @@ +{ + "openapi" : "3.1.0", + "components" : { + "schemas" : { + "Bean" : { + "type" : "object", + "properties" : { + "list" : { + "type" : "array", + "items" : { + "type" : "array", + "items" : { + "type" : "array", + "items" : { + "type" : "number", + "format" : "double" + } + } + }, + "description" : "Multi-dimensional Array.", + "examples" : [ [ [ [ 1.23, 1.0903 ] ] ] ] + }, + "mapOfLists" : { + "type" : "object", + "additionalProperties" : { + "type" : "array", + "items" : { + "type" : "array", + "items" : { + "type" : "array", + "items" : { + "type" : "number", + "format" : "double" + } + } + } + }, + "description" : "Multi-dimensional Array.", + "examples" : [ { + "data" : [ [ [ 1.23, 1.0903 ] ] ] + } ] + } + } + } + } + } +}