1616import com .fasterxml .jackson .databind .BeanDescription ;
1717import com .fasterxml .jackson .databind .JavaType ;
1818import com .fasterxml .jackson .databind .JsonNode ;
19+ import com .fasterxml .jackson .databind .JsonMappingException ;
1920import com .fasterxml .jackson .databind .ObjectMapper ;
2021import com .fasterxml .jackson .databind .PropertyMetadata ;
22+ import com .fasterxml .jackson .databind .SerializationConfig ;
2123import com .fasterxml .jackson .databind .SerializationFeature ;
2224import com .fasterxml .jackson .databind .annotation .JsonSerialize ;
2325import com .fasterxml .jackson .databind .introspect .Annotated ;
2830import com .fasterxml .jackson .databind .introspect .BeanPropertyDefinition ;
2931import com .fasterxml .jackson .databind .introspect .POJOPropertyBuilder ;
3032import com .fasterxml .jackson .databind .jsontype .NamedType ;
33+ import com .fasterxml .jackson .databind .jsontype .TypeIdResolver ;
34+ import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
3135import com .fasterxml .jackson .databind .util .Annotations ;
3236import io .swagger .v3 .core .converter .AnnotatedType ;
3337import io .swagger .v3 .core .converter .ModelConverter ;
@@ -967,7 +971,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
967971 model .setDiscriminator (null );
968972 }
969973
970- Discriminator discriminator = resolveDiscriminator (type , context );
974+ Discriminator discriminator = resolveDiscriminator (model , beanDesc , context , annotatedType . getJsonViewAnnotation () );
971975 if (discriminator != null ) {
972976 model .setDiscriminator (discriminator );
973977 }
@@ -2668,22 +2672,63 @@ protected Map<String, Object> resolveExtensions(Annotated a, Annotation[] annota
26682672 return null ;
26692673 }
26702674
2675+ protected TypeSerializer getTypeSerializer (JavaType type ) {
2676+ SerializationConfig config = _mapper .getSerializationConfig ();
2677+
2678+ try {
2679+ return _mapper .getSerializerFactory ().createTypeSerializer (
2680+ config , type
2681+ );
2682+ } catch (JsonMappingException e ) {
2683+ LOGGER .error ("Unable to create type serializer" , e );
2684+ }
2685+
2686+ return null ;
2687+ }
2688+
2689+ protected TypeSerializer getTypeSerializerForDiscriminatorInference (JavaType type ) {
2690+ // longer method would involve AnnotationIntrospector.findTypeResolver(...) but:
2691+ JsonTypeInfo typeInfo = type .getRawClass ().getDeclaredAnnotation (JsonTypeInfo .class );
2692+ if (typeInfo == null || typeInfo .use () == JsonTypeInfo .Id .NONE ) {
2693+ return null ;
2694+ }
2695+
2696+ TypeSerializer serializer = getTypeSerializer (type );
2697+ if (serializer == null ) {
2698+ return null ;
2699+ }
2700+
2701+ JsonTypeInfo .As include = serializer .getTypeInclusion ();
2702+ if (
2703+ !(
2704+ include == JsonTypeInfo .As .PROPERTY
2705+ || include == JsonTypeInfo .As .EXISTING_PROPERTY
2706+ || include == JsonTypeInfo .As .WRAPPER_OBJECT
2707+ )
2708+ ) {
2709+ return null ;
2710+ }
2711+
2712+ return serializer ;
2713+ }
2714+
26712715 protected void resolveDiscriminatorProperty (JavaType type , ModelConverterContext context , Schema model ) {
26722716 // add JsonTypeInfo.property if not member of bean
2673- JsonTypeInfo typeInfo = type .getRawClass ().getDeclaredAnnotation (JsonTypeInfo .class );
2674- if (typeInfo != null ) {
2675- String typeInfoProp = typeInfo .property ();
2676- if (StringUtils .isNotBlank (typeInfoProp )) {
2677- Schema modelToUpdate = model ;
2678- if (StringUtils .isNotBlank (model .get$ref ())) {
2679- modelToUpdate = context .getDefinedModels ().get (model .get$ref ().substring (SCHEMA_COMPONENT_PREFIX ));
2680- }
2681- if (modelToUpdate .getProperties () == null || !modelToUpdate .getProperties ().keySet ().contains (typeInfoProp )) {
2682- Schema discriminatorSchema = openapi31 ? new JsonSchema ().typesItem ("string" ).name (typeInfoProp ) : new StringSchema ().name (typeInfoProp );
2683- modelToUpdate .addProperties (typeInfoProp , discriminatorSchema );
2684- if (modelToUpdate .getRequired () == null || !modelToUpdate .getRequired ().contains (typeInfoProp )) {
2685- modelToUpdate .addRequiredItem (typeInfoProp );
2686- }
2717+ TypeSerializer serializer = getTypeSerializerForDiscriminatorInference (type );
2718+ if (serializer == null ) {
2719+ return ;
2720+ }
2721+ String propertyName = serializer .getPropertyName ();
2722+ if (StringUtils .isNotBlank (propertyName )) {
2723+ Schema modelToUpdate = model ;
2724+ if (StringUtils .isNotBlank (model .get$ref ())) {
2725+ modelToUpdate = context .getDefinedModels ().get (model .get$ref ().substring (SCHEMA_COMPONENT_PREFIX ));
2726+ }
2727+ if (modelToUpdate .getProperties () == null || !modelToUpdate .getProperties ().keySet ().contains (propertyName )) {
2728+ Schema discriminatorSchema = openapi31 ? new JsonSchema ().typesItem ("string" ).name (propertyName ) : new StringSchema ().name (propertyName );
2729+ modelToUpdate .addProperties (propertyName , discriminatorSchema );
2730+ if (modelToUpdate .getRequired () == null || !modelToUpdate .getRequired ().contains (propertyName )) {
2731+ modelToUpdate .addRequiredItem (propertyName );
26872732 }
26882733 }
26892734 }
@@ -2722,23 +2767,23 @@ protected Schema resolveWrapping(JavaType type, ModelConverterContext context, S
27222767 return model ;
27232768 }
27242769
2725- protected Discriminator resolveDiscriminator (JavaType type , ModelConverterContext context ) {
2770+ protected Discriminator resolveDiscriminator (Schema model , BeanDescription bean , ModelConverterContext context , JsonView jsonViewAnnotation ) {
2771+ io .swagger .v3 .oas .annotations .media .Schema declaredSchemaAnnotation = AnnotationsUtils .getSchemaDeclaredAnnotation (bean .getType ().getRawClass ());
27262772
2727- io .swagger .v3 .oas .annotations .media .Schema declaredSchemaAnnotation = AnnotationsUtils .getSchemaDeclaredAnnotation (type .getRawClass ());
2773+ if (declaredSchemaAnnotation != null ) {
2774+ String propertyName = declaredSchemaAnnotation .discriminatorProperty ();
27282775
2729- String disc = (declaredSchemaAnnotation == null ) ? "" : declaredSchemaAnnotation .discriminatorProperty ();
2730-
2731- if (disc .isEmpty ()) {
2732- // longer method would involve AnnotationIntrospector.findTypeResolver(...) but:
2733- JsonTypeInfo typeInfo = type .getRawClass ().getDeclaredAnnotation (JsonTypeInfo .class );
2734- if (typeInfo != null ) {
2735- disc = typeInfo .property ();
2776+ if (StringUtils .isBlank (propertyName )) {
2777+ TypeSerializer serializer = getTypeSerializerForDiscriminatorInference (bean .getType ());
2778+ if (serializer == null ) {
2779+ return null ;
2780+ }
2781+ propertyName = serializer .getPropertyName ();
27362782 }
2737- }
2738- if (!disc .isEmpty ()) {
2739- Discriminator discriminator = new Discriminator ()
2740- .propertyName (disc );
2741- if (declaredSchemaAnnotation != null ) {
2783+
2784+ if (StringUtils .isNotBlank (propertyName )) {
2785+ Discriminator discriminator = new Discriminator ().propertyName (propertyName );
2786+
27422787 DiscriminatorMapping [] mappings = declaredSchemaAnnotation .discriminatorMapping ();
27432788 if (mappings != null && mappings .length > 0 ) {
27442789 for (DiscriminatorMapping mapping : mappings ) {
@@ -2747,11 +2792,62 @@ protected Discriminator resolveDiscriminator(JavaType type, ModelConverterContex
27472792 }
27482793 }
27492794 }
2795+
2796+ return discriminator ;
27502797 }
2798+ }
27512799
2752- return discriminator ;
2800+ TypeSerializer serializer = getTypeSerializerForDiscriminatorInference (bean .getType ());
2801+ if (serializer == null ) {
2802+ return null ;
27532803 }
2754- return null ;
2804+ String propertyName = serializer .getPropertyName ();
2805+ if (StringUtils .isBlank (propertyName )) {
2806+ return null ;
2807+ }
2808+
2809+ Discriminator discriminator = new Discriminator ().propertyName (propertyName );
2810+
2811+ // Use same approach to finding subtypes as resolveSubtypes, mimicking
2812+ final List <NamedType > subTypes = _intr ().findSubtypes (bean .getClassInfo ());
2813+ if (subTypes == null ) {
2814+ return null ;
2815+ }
2816+
2817+ removeSuperClassAndInterfaceSubTypes (subTypes , bean );
2818+
2819+ final Class <?> beanClass = bean .getClassInfo ().getAnnotated ();
2820+ if (!subTypes .isEmpty ()) {
2821+ TypeIdResolver resolver = serializer .getTypeIdResolver ();
2822+
2823+ for (NamedType subType : subTypes ) {
2824+ final Class <?> subtypeType = subType .getType ();
2825+ if (!beanClass .isAssignableFrom (subtypeType )) {
2826+ continue ;
2827+ }
2828+
2829+ String subTypeName = resolver .idFromValueAndType (null , subType .getType ());
2830+
2831+ final Schema subtypeModel = context .resolve (new AnnotatedType ()
2832+ .type (subtypeType )
2833+ .jsonViewAnnotation (jsonViewAnnotation )
2834+ .subtype (true ));
2835+
2836+ if (StringUtils .isBlank (subtypeModel .getName ()) ||
2837+ subtypeModel .getName ().equals (model .getName ())) {
2838+ subtypeModel .setName (_typeNameResolver .nameForType (_mapper .constructType (subtypeType ),
2839+ TypeNameResolver .Options .SKIP_API_MODEL ));
2840+ }
2841+
2842+ // Per the specification, there is an implicit map to schemas with the same name
2843+ // We skip writing the mappings that are implied to keep the schema minimal
2844+ if (!subTypeName .equals (subtypeModel .getName ())) {
2845+ discriminator .mapping (subTypeName , RefUtils .constructRef (subtypeModel .getName ()));
2846+ }
2847+ }
2848+ }
2849+
2850+ return discriminator ;
27552851 }
27562852
27572853 protected XML resolveXml (Annotated a , Annotation [] annotations , io .swagger .v3 .oas .annotations .media .Schema schema ) {
0 commit comments