Skip to content

Commit ce50154

Browse files
refactor: simplify discriminatorFound logic and move it to the DiscriminatorUtils
1 parent df45e93 commit ce50154

2 files changed

Lines changed: 141 additions & 137 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 2 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,110 +3343,6 @@ protected void setAddProps(Schema schema, IJsonSchemaValidationProperties proper
33433343
}
33443344
}
33453345

3346-
/**
3347-
* Recursively look in Schema sc for the discriminator discPropName
3348-
* and return a CodegenProperty with the dataType and required params set
3349-
* the returned CodegenProperty may not be required and it may not be of type string
3350-
*
3351-
* @param composedSchemaName The name of the sc Schema
3352-
* @param sc The Schema that may contain the discriminator
3353-
* @param discPropName The String that is the discriminator propertyName in the schema
3354-
* @param visitedSchemas A set of visited schema names
3355-
*/
3356-
private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, String discPropName, Set<String> visitedSchemas) {
3357-
Schema refSchema = ModelUtils.getReferencedSchema(openAPI, sc);
3358-
String schemaName = Optional.ofNullable(composedSchemaName)
3359-
.or(() -> Optional.ofNullable(refSchema.getName()))
3360-
.or(() -> Optional.ofNullable(sc.get$ref()).map(ModelUtils::getSimpleRef))
3361-
.orElseGet(sc::toString);
3362-
if (visitedSchemas.contains(schemaName)) { // recursive schema definition found
3363-
return null;
3364-
} else {
3365-
visitedSchemas.add(schemaName);
3366-
}
3367-
3368-
if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) {
3369-
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, getDiscriminatorSchema(refSchema, discPropName));
3370-
CodegenProperty cp = new CodegenProperty();
3371-
if (ModelUtils.isStringSchema(discSchema)) {
3372-
cp.isString = true;
3373-
}
3374-
cp.setRequired(false);
3375-
if (refSchema.getRequired() != null && refSchema.getRequired().contains(discPropName)) {
3376-
cp.setRequired(true);
3377-
}
3378-
cp.setIsEnum(discSchema.getEnum() != null && !discSchema.getEnum().isEmpty());
3379-
return cp;
3380-
}
3381-
if (ModelUtils.isComposedSchema(refSchema)) {
3382-
Schema composedSchema = refSchema;
3383-
if (composedSchema.getAllOf() != null) {
3384-
// If our discriminator is in one of the allOf schemas break when we find it
3385-
for (Object allOf : composedSchema.getAllOf()) {
3386-
Schema allOfSchema = (Schema) allOf;
3387-
CodegenProperty cp = discriminatorFound(allOfSchema.getName(), allOfSchema, discPropName, visitedSchemas);
3388-
if (cp != null) {
3389-
return cp;
3390-
}
3391-
}
3392-
}
3393-
if (ModelUtils.hasOneOf(composedSchema)) {
3394-
// All oneOf definitions must contain the discriminator
3395-
CodegenProperty cp = new CodegenProperty();
3396-
for (Object oneOf : composedSchema.getOneOf()) {
3397-
Schema oneOfSchema = (Schema) oneOf;
3398-
String modelName = ModelUtils.getSimpleRef((oneOfSchema).get$ref());
3399-
// Must use a copied set as the oneOf schemas can point to the same discriminator.
3400-
Set<String> visitedSchemasCopy = new TreeSet<>(visitedSchemas);
3401-
CodegenProperty thisCp = discriminatorFound(oneOfSchema.getName(), oneOfSchema, discPropName, visitedSchemasCopy);
3402-
if (thisCp == null) {
3403-
once(LOGGER).warn(
3404-
"'{}' defines discriminator '{}', but the referenced OneOf schema '{}' is missing {}",
3405-
composedSchemaName, discPropName, modelName, discPropName);
3406-
}
3407-
if (cp != null && cp.dataType == null) {
3408-
cp = thisCp;
3409-
continue;
3410-
}
3411-
if (cp != thisCp) {
3412-
once(LOGGER).warn(
3413-
"'{}' defines discriminator '{}', but the OneOf schema '{}' has a different {} definition than the prior OneOf schema's. Make sure the {} type and required values are the same",
3414-
composedSchemaName, discPropName, modelName, discPropName, discPropName);
3415-
}
3416-
}
3417-
return cp;
3418-
}
3419-
if (ModelUtils.hasAnyOf(composedSchema)) {
3420-
// All anyOf definitions must contain the discriminator because a min of one must be selected
3421-
CodegenProperty cp = new CodegenProperty();
3422-
for (Object anyOf : composedSchema.getAnyOf()) {
3423-
Schema anyOfSchema = (Schema) anyOf;
3424-
String modelName = ModelUtils.getSimpleRef(anyOfSchema.get$ref());
3425-
// Must use a copied set as the anyOf schemas can point to the same discriminator.
3426-
Set<String> visitedSchemasCopy = new TreeSet<>(visitedSchemas);
3427-
CodegenProperty thisCp = discriminatorFound(anyOfSchema.getName(), anyOfSchema, discPropName, visitedSchemasCopy);
3428-
if (thisCp == null) {
3429-
once(LOGGER).warn(
3430-
"'{}' defines discriminator '{}', but the referenced AnyOf schema '{}' is missing {}",
3431-
composedSchemaName, discPropName, modelName, discPropName);
3432-
}
3433-
if (cp != null && cp.dataType == null) {
3434-
cp = thisCp;
3435-
continue;
3436-
}
3437-
if (cp != thisCp) {
3438-
once(LOGGER).warn(
3439-
"'{}' defines discriminator '{}', but the AnyOf schema '{}' has a different {} definition than the prior AnyOf schema's. Make sure the {} type and required values are the same",
3440-
composedSchemaName, discPropName, modelName, discPropName, discPropName);
3441-
}
3442-
}
3443-
return cp;
3444-
3445-
}
3446-
}
3447-
return null;
3448-
}
3449-
34503346
/**
34513347
* Recursively look in Schema sc for the discriminator and return it
34523348
*
@@ -3495,7 +3391,7 @@ protected List<MappedModel> getOneOfAnyOfDescendants(String composedSchemaName,
34953391
"Invalid inline schema defined in oneOf/anyOf in '{}'. Per the OpenApi spec, for this case when a composed schema defines a discriminator, the oneOf/anyOf schemas must use $ref. Change this inline definition to a $ref definition",
34963392
composedSchemaName);
34973393
}
3498-
CodegenProperty df = discriminatorFound(composedSchemaName, sc, discPropName, new TreeSet<String>());
3394+
CodegenProperty df = DiscriminatorUtils.discriminatorFound(openAPI, composedSchemaName, sc, discPropName, new TreeSet<String>());
34993395
String modelName = ModelUtils.getSimpleRef(ref);
35003396
if (df == null || !df.isString || !df.required) {
35013397
String msgSuffix = "";
@@ -3611,7 +3507,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
36113507

36123508
// check to see if the discriminator property is an enum string
36133509
boolean isEnum = Optional
3614-
.ofNullable(discriminatorFound(schemaName, schema, discriminatorPropertyName, new TreeSet<>()))
3510+
.ofNullable(DiscriminatorUtils.discriminatorFound(openAPI, schemaName, schema, discriminatorPropertyName, new TreeSet<>()))
36153511
.map(CodegenProperty::getIsEnum)
36163512
.orElse(false);
36173513
discriminator.setIsEnum(isEnum);
@@ -3671,18 +3567,6 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
36713567
return discriminator;
36723568
}
36733569

3674-
/**
3675-
* Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
3676-
* An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
3677-
* referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
3678-
*
3679-
* @param schema The input OAS schema.
3680-
* @param discriminatorName The name of the discriminator property.
3681-
*/
3682-
protected Schema getDiscriminatorSchema(Schema schema, String discriminatorName) {
3683-
return DiscriminatorUtils.getDiscriminatorSchema(schema, discriminatorName);
3684-
}
3685-
36863570
/**
36873571
* Get the property type for the discriminator
36883572
*

modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/DiscriminatorUtils.java

Lines changed: 139 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.swagger.v3.oas.models.OpenAPI;
44
import io.swagger.v3.oas.models.media.Discriminator;
55
import io.swagger.v3.oas.models.media.Schema;
6+
import org.openapitools.codegen.CodegenProperty;
67
import org.slf4j.Logger;
78
import 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

Comments
 (0)