33import io .swagger .v3 .oas .models .OpenAPI ;
44import io .swagger .v3 .oas .models .media .Discriminator ;
55import io .swagger .v3 .oas .models .media .Schema ;
6+ import org .openapitools .codegen .CodegenProperty ;
67import org .slf4j .Logger ;
78import org .slf4j .LoggerFactory ;
89
@@ -16,6 +17,91 @@ public class DiscriminatorUtils {
1617
1718 private static final String CONFLICTING_DISCRIMINATOR_NAMES =
1819 "The alternative schemas have conflicting discriminator property names. The schemas must have the same property name, but found {}" ;
20+ private static final String DEFINES_DISCRIMINATOR_BUT_REFERENCE_ALTERNATIVE_IS_MISSING =
21+ "'{}' defines discriminator '{}', but the referenced schema '{}' is missing {}" ;
22+ private static final String DEFINES_DISCRIMINATOR_BUT_ALTERNATIVE_HAS_OTHER_DEFINITION =
23+ "'{}' defines discriminator '{}', but the schema '{}' has a different {} definition than the prior schema's. Make sure the {} type and required values are the same" ;
24+
25+ /**
26+ * Recursively look in Schema sc for the discriminator discPropName
27+ * and return a CodegenProperty with the dataType and required params set
28+ * the returned CodegenProperty may not be required, and it may not be of type string
29+ *
30+ * @param openAPI The openAPI specification
31+ * @param composedSchemaName The name of the sc Schema
32+ * @param sc The Schema that may contain the discriminator
33+ * @param discPropName The String that is the discriminator propertyName in the schema
34+ * @param visitedSchemas A set of visited schema names
35+ */
36+ public static CodegenProperty discriminatorFound (OpenAPI openAPI ,
37+ String composedSchemaName ,
38+ Schema sc ,
39+ String discPropName ,
40+ Set <String > visitedSchemas ) {
41+ Schema refSchema = ModelUtils .getReferencedSchema (openAPI , sc );
42+ String schemaName = Optional .ofNullable (composedSchemaName )
43+ .or (() -> Optional .ofNullable (refSchema .getName ()))
44+ .or (() -> Optional .ofNullable (sc .get$ref ()).map (ModelUtils ::getSimpleRef ))
45+ .orElseGet (sc ::toString );
46+ if (visitedSchemas .contains (schemaName )) { // recursive schema definition found
47+ return null ;
48+ } else {
49+ visitedSchemas .add (schemaName );
50+ }
51+
52+ if (refSchema .getProperties () != null && refSchema .getProperties ().get (discPropName ) != null ) {
53+ Schema discSchema = ModelUtils .getReferencedSchema (openAPI , getDiscriminatorSchema (refSchema , discPropName ));
54+ CodegenProperty cp = new CodegenProperty ();
55+ if (ModelUtils .isStringSchema (discSchema )) {
56+ cp .isString = true ;
57+ }
58+ cp .setRequired (false );
59+ if (refSchema .getRequired () != null && refSchema .getRequired ().contains (discPropName )) {
60+ cp .setRequired (true );
61+ }
62+ cp .setIsEnum (discSchema .getEnum () != null && !discSchema .getEnum ().isEmpty ());
63+ return cp ;
64+ }
65+ if (ModelUtils .isComposedSchema (refSchema )) {
66+ Schema composedSchema = refSchema ;
67+ if (composedSchema .getAllOf () != null ) {
68+ // If our discriminator is in one of the allOf schemas break when we find it
69+ for (Object allOf : composedSchema .getAllOf ()) {
70+ Schema allOfSchema = (Schema ) allOf ;
71+ CodegenProperty cp = discriminatorFound (openAPI , allOfSchema .getName (), allOfSchema , discPropName , visitedSchemas );
72+ if (cp != null ) {
73+ return cp ;
74+ }
75+ }
76+ }
77+ if (ModelUtils .hasOneOf (composedSchema )) {
78+ // All oneOf definitions must contain the discriminator
79+ CodegenProperty cp = new CodegenProperty ();
80+ for (Object oneOf : composedSchema .getOneOf ()) {
81+ Schema oneOfSchema = (Schema ) oneOf ;
82+ CodegenProperty discCP = getDiscriminatorCodegenProperty (openAPI , cp , composedSchemaName , oneOfSchema , discPropName , visitedSchemas );
83+ if (discCP != null ) {
84+ cp = discCP ;
85+ }
86+ }
87+ return cp ;
88+ }
89+ if (ModelUtils .hasAnyOf (composedSchema )) {
90+ // All anyOf definitions must contain the discriminator because a min of one must be selected
91+ CodegenProperty cp = new CodegenProperty ();
92+ for (Object anyOf : composedSchema .getAnyOf ()) {
93+ Schema anyOfSchema = (Schema ) anyOf ;
94+ CodegenProperty discCP = getDiscriminatorCodegenProperty (openAPI , cp , composedSchemaName , anyOfSchema , discPropName , visitedSchemas );
95+ if (discCP != null ) {
96+ cp = discCP ;
97+ }
98+ }
99+ return cp ;
100+
101+ }
102+ }
103+ return null ;
104+ }
19105
20106 /**
21107 * Gets the simple ref name of the discriminator property type from the schema.
@@ -30,25 +116,6 @@ public static Optional<String> getDiscriminatorPropertyType(Schema schema, Strin
30116 .map (ModelUtils ::getSimpleRef );
31117 }
32118
33- /**
34- * Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
35- * An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
36- * referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
37- *
38- * @param schema The input OAS schema.
39- * @param discriminatorName The name of the discriminator property.
40- */
41- public static Schema getDiscriminatorSchema (Schema schema , String discriminatorName ) {
42- if (schema .getProperties () == null ) {
43- return null ;
44- }
45- Schema discSchema = (Schema ) schema .getProperties ().get (discriminatorName );
46- if (ModelUtils .isAllOf (discSchema )) {
47- discSchema = (Schema ) discSchema .getAllOf ().get (0 );
48- }
49- return discSchema ;
50- }
51-
52119 /**
53120 * Recursively look in Schema sc for the discriminator and return it
54121 *
@@ -106,6 +173,25 @@ public static Discriminator recursiveGetDiscriminator(
106173 return null ;
107174 }
108175
176+ /**
177+ * Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
178+ * An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
179+ * referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
180+ *
181+ * @param schema The input OAS schema.
182+ * @param discriminatorName The name of the discriminator property.
183+ */
184+ private static Schema getDiscriminatorSchema (Schema schema , String discriminatorName ) {
185+ if (schema .getProperties () == null ) {
186+ return null ;
187+ }
188+ Schema discSchema = (Schema ) schema .getProperties ().get (discriminatorName );
189+ if (ModelUtils .isAllOf (discSchema )) {
190+ discSchema = (Schema ) discSchema .getAllOf ().get (0 );
191+ }
192+ return discSchema ;
193+ }
194+
109195 /**
110196 * Check whether the alternative schemas share a discriminator, and if they do, return it
111197 *
@@ -151,4 +237,38 @@ private static Discriminator getDiscriminatorFromAlternatives(
151237 return null ;
152238 }
153239
240+ /**
241+ * Recursively look in schema for the discriminator discPropName
242+ *
243+ * @param openAPI The openAPI specification
244+ * @param cp Any previously calculated discriminator codegen property
245+ * @param composedSchemaName The name of the sc Schema
246+ * @param schema The Schema that may contain the discriminator
247+ * @param discPropName The String that is the discriminator propertyName in the schema
248+ * @param visitedSchemas A set of visited schema names
249+ */
250+ private static CodegenProperty getDiscriminatorCodegenProperty (OpenAPI openAPI ,
251+ CodegenProperty cp ,
252+ String composedSchemaName ,
253+ Schema schema ,
254+ String discPropName ,
255+ Set <String > visitedSchemas ) {
256+ String modelName = ModelUtils .getSimpleRef (schema .get$ref ());
257+ // Must use a copied set as the alternative schemas can point to the same discriminator.
258+ Set <String > visitedSchemasCopy = new TreeSet <>(visitedSchemas );
259+ CodegenProperty thisCp = discriminatorFound (openAPI , schema .getName (), schema , discPropName , visitedSchemasCopy );
260+ if (thisCp == null ) {
261+ once (LOGGER ).warn (DEFINES_DISCRIMINATOR_BUT_REFERENCE_ALTERNATIVE_IS_MISSING ,
262+ composedSchemaName , discPropName , modelName , discPropName );
263+ }
264+ if (cp != null && cp .dataType == null ) {
265+ return thisCp ;
266+ }
267+ if (cp != thisCp ) {
268+ once (LOGGER ).warn (DEFINES_DISCRIMINATOR_BUT_ALTERNATIVE_HAS_OTHER_DEFINITION ,
269+ composedSchemaName , discPropName , modelName , discPropName , discPropName );
270+ }
271+ return null ;
272+ }
273+
154274}
0 commit comments