diff --git a/openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiVisitor.java b/openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiVisitor.java index d5158d8747..8cc4fde091 100644 --- a/openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiVisitor.java +++ b/openapi/src/main/java/io/micronaut/openapi/visitor/AbstractOpenApiVisitor.java @@ -214,6 +214,7 @@ import static io.micronaut.openapi.visitor.StringUtil.SLASH; import static io.micronaut.openapi.visitor.StringUtil.UNDERSCORE; import static io.micronaut.openapi.visitor.Utils.isOpenapi31; +import static io.micronaut.openapi.visitor.Utils.resolveOpenApi; import static java.util.stream.Collectors.toMap; /** @@ -1172,9 +1173,14 @@ private Schema processGenericAnnotations(Schema schema, ClassElement compo private void handleUnwrapped(VisitorContext context, Element element, ClassElement elementType, Schema parentSchema, AnnotationValue uw) { Map schemas = SchemaUtils.resolveSchemas(Utils.resolveOpenApi(context)); ClassElement customElementType = getCustomSchema(elementType.getName(), elementType.getTypeArguments(), context); + var elType = customElementType != null ? customElementType : elementType; String schemaName = stringValue(element, io.swagger.v3.oas.annotations.media.Schema.class, PROP_NAME) - .orElse(computeDefaultSchemaName(null, customElementType != null ? customElementType : elementType, elementType.getTypeArguments(), context, null)); + .orElse(computeDefaultSchemaName(null, elType, elementType.getTypeArguments(), context, null)); Schema wrappedPropertySchema = schemas.get(schemaName); + if (wrappedPropertySchema == null) { + getSchemaDefinition(resolveOpenApi(context), context, elType, elType.getTypeArguments(), element, Collections.emptyList(), null); + wrappedPropertySchema = schemas.get(schemaName); + } Map properties = wrappedPropertySchema.getProperties(); if (CollectionUtils.isEmpty(properties)) { return; diff --git a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiJsonUnwrappedsSpec.groovy b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiJsonUnwrappedsSpec.groovy index 73a49a1b61..856b4c71f5 100644 --- a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiJsonUnwrappedsSpec.groovy +++ b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiJsonUnwrappedsSpec.groovy @@ -8,7 +8,7 @@ class OpenApiJsonUnwrappedsSpec extends AbstractOpenApiTypeElementSpec { void "test JsonUnwrapped annotation"() { - given:"An API definition" + given: "An API definition" when: buildBeanDefinition('test.MyBean', ''' package test; @@ -91,16 +91,16 @@ class Test { @jakarta.inject.Singleton class MyBean {} ''') - then:"the state is correct" + then: "the state is correct" Utils.testReference != null - when:"The OpenAPI is retrieved" + when: "The OpenAPI is retrieved" OpenAPI openAPI = Utils.testReference Schema schema = openAPI.components.schemas['Test'] Schema dummySchema = openAPI.components.schemas['Dummy'] Schema petSchema = openAPI.components.schemas['Pet'] - then:"the components are valid" + then: "the components are valid" schema.type == 'object' schema.properties.size() == 13 schema.properties['plain'].$ref == '#/components/schemas/Dummy' @@ -176,4 +176,50 @@ class MyBean {} exampleSchema.properties.nameInJson.type == 'string' exampleSchema.properties.nameInJson.description == 'example field' } + + void "test issue with JsonUnwrapped and wildcard response type"() { + + given: "An API definition" + when: + buildBeanDefinition('test.MyBean', ''' +package test; + +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Post; +import io.reactivex.Single; + +@Controller("/test") +interface TestOperations { + + @Post + Single> save(String name, int age); +} + +class Base { + + public String name; +} + +class Test { + @JsonUnwrapped + public T wrapped; +} + +@jakarta.inject.Singleton +class MyBean {} +''') + then: "the state is correct" + Utils.testReference != null + + when: "The OpenAPI is retrieved" + def openApi = Utils.testReference + Schema schema = openApi.components.schemas.Test_Base_ + + then: "the components are valid" + schema.type == 'object' + schema.properties + schema.properties.size() == 1 + schema.properties.name + } }