From 55e455dee8656d920977c93de89c134611e26f73 Mon Sep 17 00:00:00 2001 From: Mattias-Sehlstedt <60173714+Mattias-Sehlstedt@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:03:49 +0200 Subject: [PATCH] refactor: add DiscriminatorResolver for handling discriminator properties in schemas --- .../core/jackson/DiscriminatorResolver.java | 79 +++++++++++++++++++ .../v3/core/jackson/ModelResolver.java | 50 +----------- 2 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/DiscriminatorResolver.java diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/DiscriminatorResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/DiscriminatorResolver.java new file mode 100644 index 0000000000..db1793d0cb --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/DiscriminatorResolver.java @@ -0,0 +1,79 @@ +package io.swagger.v3.core.jackson; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.JavaType; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.util.AnnotationsUtils; +import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; +import io.swagger.v3.oas.models.media.Discriminator; +import io.swagger.v3.oas.models.media.JsonSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import org.apache.commons.lang3.StringUtils; + +import static io.swagger.v3.core.util.RefUtils.constructRef; + +class DiscriminatorResolver { + + private DiscriminatorResolver() { + } + + private static final int SCHEMA_COMPONENT_PREFIX = "#/components/schemas/".length(); + private static final String TYPE_STRING = "string"; + + public static void resolveDiscriminatorProperty(JavaType type, + ModelConverterContext context, + Schema model, + boolean openapi31) { + // add JsonTypeInfo.property if not member of bean + JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class); + if (typeInfo != null) { + String typeInfoProp = typeInfo.property(); + if (StringUtils.isNotBlank(typeInfoProp)) { + Schema modelToUpdate = model; + if (StringUtils.isNotBlank(model.get$ref())) { + modelToUpdate = context.getDefinedModels().get(model.get$ref().substring(SCHEMA_COMPONENT_PREFIX)); + } + if (modelToUpdate.getProperties() == null || !modelToUpdate.getProperties().keySet().contains(typeInfoProp)) { + Schema discriminatorSchema = openapi31 ? new JsonSchema().typesItem(TYPE_STRING).name(typeInfoProp) : new StringSchema().name(typeInfoProp); + modelToUpdate.addProperties(typeInfoProp, discriminatorSchema); + if (modelToUpdate.getRequired() == null || !modelToUpdate.getRequired().contains(typeInfoProp)) { + modelToUpdate.addRequiredItem(typeInfoProp); + } + } + } + } + } + + public static Discriminator resolveDiscriminator(JavaType type, ModelConverterContext context) { + io.swagger.v3.oas.annotations.media.Schema declaredSchemaAnnotation = AnnotationsUtils.getSchemaDeclaredAnnotation(type.getRawClass()); + + String disc = (declaredSchemaAnnotation == null) ? "" : declaredSchemaAnnotation.discriminatorProperty(); + + if (disc.isEmpty()) { + // longer method would involve AnnotationIntrospector.findTypeResolver(...) but: + JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class); + if (typeInfo != null) { + disc = typeInfo.property(); + } + } + if (!disc.isEmpty()) { + Discriminator discriminator = new Discriminator() + .propertyName(disc); + if (declaredSchemaAnnotation != null) { + DiscriminatorMapping[] mappings = declaredSchemaAnnotation.discriminatorMapping(); + if (mappings != null && mappings.length > 0) { + for (DiscriminatorMapping mapping : mappings) { + if (!mapping.value().isEmpty() && !mapping.schema().equals(Void.class)) { + discriminator.mapping(mapping.value(), constructRef(context.resolve(new AnnotatedType().type(mapping.schema())).getName())); + } + } + } + } + + return discriminator; + } + return null; + } +} diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java index b281d34855..3980628288 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java @@ -40,7 +40,6 @@ import io.swagger.v3.oas.annotations.media.DependentRequired; import io.swagger.v3.oas.annotations.media.DependentSchema; import io.swagger.v3.oas.annotations.media.DependentSchemas; -import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; import io.swagger.v3.oas.annotations.media.PatternProperties; import io.swagger.v3.oas.annotations.media.PatternProperty; import io.swagger.v3.oas.annotations.media.SchemaProperties; @@ -2694,24 +2693,7 @@ protected Map resolveExtensions(Annotated a, Annotation[] annota } protected void resolveDiscriminatorProperty(JavaType type, ModelConverterContext context, Schema model) { - // add JsonTypeInfo.property if not member of bean - JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class); - if (typeInfo != null) { - String typeInfoProp = typeInfo.property(); - if (StringUtils.isNotBlank(typeInfoProp)) { - Schema modelToUpdate = model; - if (StringUtils.isNotBlank(model.get$ref())) { - modelToUpdate = context.getDefinedModels().get(model.get$ref().substring(SCHEMA_COMPONENT_PREFIX)); - } - if (modelToUpdate.getProperties() == null || !modelToUpdate.getProperties().keySet().contains(typeInfoProp)) { - Schema discriminatorSchema = openapi31 ? new JsonSchema().typesItem("string").name(typeInfoProp) : new StringSchema().name(typeInfoProp); - modelToUpdate.addProperties(typeInfoProp, discriminatorSchema); - if (modelToUpdate.getRequired() == null || !modelToUpdate.getRequired().contains(typeInfoProp)) { - modelToUpdate.addRequiredItem(typeInfoProp); - } - } - } - } + DiscriminatorResolver.resolveDiscriminatorProperty(type, context, model, openapi31); } /* @@ -2748,35 +2730,7 @@ protected Schema resolveWrapping(JavaType type, ModelConverterContext context, S } protected Discriminator resolveDiscriminator(JavaType type, ModelConverterContext context) { - - io.swagger.v3.oas.annotations.media.Schema declaredSchemaAnnotation = AnnotationsUtils.getSchemaDeclaredAnnotation(type.getRawClass()); - - String disc = (declaredSchemaAnnotation == null) ? "" : declaredSchemaAnnotation.discriminatorProperty(); - - if (disc.isEmpty()) { - // longer method would involve AnnotationIntrospector.findTypeResolver(...) but: - JsonTypeInfo typeInfo = type.getRawClass().getDeclaredAnnotation(JsonTypeInfo.class); - if (typeInfo != null) { - disc = typeInfo.property(); - } - } - if (!disc.isEmpty()) { - Discriminator discriminator = new Discriminator() - .propertyName(disc); - if (declaredSchemaAnnotation != null) { - DiscriminatorMapping[] mappings = declaredSchemaAnnotation.discriminatorMapping(); - if (mappings != null && mappings.length > 0) { - for (DiscriminatorMapping mapping : mappings) { - if (!mapping.value().isEmpty() && !mapping.schema().equals(Void.class)) { - discriminator.mapping(mapping.value(), constructRef(context.resolve(new AnnotatedType().type(mapping.schema())).getName())); - } - } - } - } - - return discriminator; - } - return null; + return DiscriminatorResolver.resolveDiscriminator(type, context); } protected XML resolveXml(Annotated a, Annotation[] annotations, io.swagger.v3.oas.annotations.media.Schema schema) {