diff --git a/serde-jackson/src/test/groovy/io/micronaut/serde/jackson/annotation/JsonTypeInfoSpec.groovy b/serde-jackson/src/test/groovy/io/micronaut/serde/jackson/annotation/JsonTypeInfoSpec.groovy index 0c2898da6..deb97013a 100644 --- a/serde-jackson/src/test/groovy/io/micronaut/serde/jackson/annotation/JsonTypeInfoSpec.groovy +++ b/serde-jackson/src/test/groovy/io/micronaut/serde/jackson/annotation/JsonTypeInfoSpec.groovy @@ -770,4 +770,47 @@ record TypeA (String a, InterfaceB b) { } cleanup: context.close() } + + void "test no properties subtype"() { + given: + def context = buildContext(""" +package subtypes; + +import com.fasterxml.jackson.annotation.*; +import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + property = "validation-type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = NonEmptyString.class, name = "NonEmptyString"), +}) +interface Validator { } + +@Serdeable +class NonEmptyString implements Validator { + } +""") + + def argument = argumentOf(context, 'subtypes.NonEmptyString') + + when: + def bean = newInstance(context, 'subtypes.NonEmptyString') + def json = writeJson(jsonMapper, bean) + + then: + json == """{"validation-type":"NonEmptyString"}""" + + + when: + def deser = jsonMapper.readValue(json, argument) + + then: + deser + argument.isInstance(deser) + + cleanup: + context.close() + } } diff --git a/serde-support/src/main/java/io/micronaut/serde/support/serializers/SerBean.java b/serde-support/src/main/java/io/micronaut/serde/support/serializers/SerBean.java index 81e5b49f9..c21d0cc59 100644 --- a/serde-support/src/main/java/io/micronaut/serde/support/serializers/SerBean.java +++ b/serde-support/src/main/java/io/micronaut/serde/support/serializers/SerBean.java @@ -181,10 +181,12 @@ public int getOrder() { initializers.add(ctx -> initProperty(ag, ctx)); } - if (!properties.isEmpty() || !jsonGetters.isEmpty()) { + AnnotationMetadata am = new AnnotationMetadataHierarchy(introspection, definition.getAnnotationMetadata()); + Optional subType = am.stringValue(SerdeConfig.class, SerdeConfig.TYPE_NAME); + + if (!properties.isEmpty() || !jsonGetters.isEmpty() || subType.isPresent()) { writeProperties = new ArrayList<>(properties.size() + jsonGetters.size()); - AnnotationMetadata am = new AnnotationMetadataHierarchy(introspection, definition.getAnnotationMetadata()); - am.stringValue(SerdeConfig.class, SerdeConfig.TYPE_NAME).ifPresent(typeName -> { + subType.ifPresent(typeName -> { String typeProperty = am.stringValue(SerdeConfig.class, SerdeConfig.TYPE_PROPERTY).orElse(null); if (typeProperty != null) { SerProperty prop;