diff --git a/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java b/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java index 419d7824c0..19643540de 100644 --- a/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java +++ b/openapi/src/main/java/io/micronaut/openapi/visitor/SchemaDefinitionUtils.java @@ -2698,6 +2698,16 @@ private static void handleUnwrapped(VisitorContext context, Element element, Cla Map schemas = SchemaUtils.resolveSchemas(Utils.resolveOpenApi(context)); ClassElement customElementType = getCustomSchema(elementType.getName(), elementType.getTypeArguments(), context); var elType = customElementType != null ? customElementType : elementType; + + // check schema annotation + var schemaAnn = element.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (schemaAnn != null) { + var implClass = schemaAnn.annotationClassValue(PROP_IMPLEMENTATION).orElse(null); + if (implClass != null) { + elType = context.getClassElement(implClass.getName()).orElse(elType); + } + } + String schemaName = computeDefaultSchemaName(stringValue(element, io.swagger.v3.oas.annotations.media.Schema.class, PROP_NAME).orElse(null), null, elType, elementType.getTypeArguments(), context, null); Schema wrappedPropertySchema = schemas.get(schemaName); diff --git a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy index 3588f1eb2c..5313aacfcf 100644 --- a/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy +++ b/openapi/src/test/groovy/io/micronaut/openapi/visitor/OpenApiSchemaFieldSpec.groovy @@ -1136,4 +1136,57 @@ class MyBean {} schemas.MyDto2.properties.field2.allOf.size() == 1 schemas.MyDto2.properties.field2.allOf[0].$ref == '#/components/schemas/MyDto' } + + void "test unwrap with custom schema implementation"() { + + when: + buildBeanDefinition('test.MyBean', ''' +package test; + +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Put; +import io.swagger.v3.oas.annotations.media.Schema; + +@Controller +class HelloController { + + @Put("/sendModelWithDiscriminator") + Car sendModelWithDiscriminator() { + return null; + } +} + +record Car( + String model, + @JsonUnwrapped @Schema(implementation = ResourcePath.class) Resource resource, + boolean selected +) { } + +abstract class Resource { +} + +abstract class ResourcePath extends Resource { + + public String resourcePath; + public String resourceType; +} + +@jakarta.inject.Singleton +class MyBean {} +''') + then: "the state is correct" + Utils.testReference != null + + when: "The OpenAPI is retrieved" + def openApi = Utils.testReference + def schemas = openApi.components.schemas + + then: "the components are valid" + schemas.Car + schemas.Car.properties.model + schemas.Car.properties.resourcePath + schemas.Car.properties.resourceType + schemas.Car.properties.selected + } }