Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3343,110 +3343,6 @@ protected void setAddProps(Schema schema, IJsonSchemaValidationProperties proper
}
}

/**
* Recursively look in Schema sc for the discriminator discPropName
* and return a CodegenProperty with the dataType and required params set
* the returned CodegenProperty may not be required and it may not be of type string
*
* @param composedSchemaName The name of the sc Schema
* @param sc The Schema that may contain the discriminator
* @param discPropName The String that is the discriminator propertyName in the schema
* @param visitedSchemas A set of visited schema names
*/
private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, String discPropName, Set<String> visitedSchemas) {
Schema refSchema = ModelUtils.getReferencedSchema(openAPI, sc);
String schemaName = Optional.ofNullable(composedSchemaName)
.or(() -> Optional.ofNullable(refSchema.getName()))
.or(() -> Optional.ofNullable(sc.get$ref()).map(ModelUtils::getSimpleRef))
.orElseGet(sc::toString);
if (visitedSchemas.contains(schemaName)) { // recursive schema definition found
return null;
} else {
visitedSchemas.add(schemaName);
}

if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) {
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, getDiscriminatorSchema(refSchema, discPropName));
CodegenProperty cp = new CodegenProperty();
if (ModelUtils.isStringSchema(discSchema)) {
cp.isString = true;
}
cp.setRequired(false);
if (refSchema.getRequired() != null && refSchema.getRequired().contains(discPropName)) {
cp.setRequired(true);
}
cp.setIsEnum(discSchema.getEnum() != null && !discSchema.getEnum().isEmpty());
return cp;
}
if (ModelUtils.isComposedSchema(refSchema)) {
Schema composedSchema = refSchema;
if (composedSchema.getAllOf() != null) {
// If our discriminator is in one of the allOf schemas break when we find it
for (Object allOf : composedSchema.getAllOf()) {
Schema allOfSchema = (Schema) allOf;
CodegenProperty cp = discriminatorFound(allOfSchema.getName(), allOfSchema, discPropName, visitedSchemas);
if (cp != null) {
return cp;
}
}
}
if (ModelUtils.hasOneOf(composedSchema)) {
// All oneOf definitions must contain the discriminator
CodegenProperty cp = new CodegenProperty();
for (Object oneOf : composedSchema.getOneOf()) {
Schema oneOfSchema = (Schema) oneOf;
String modelName = ModelUtils.getSimpleRef((oneOfSchema).get$ref());
// Must use a copied set as the oneOf schemas can point to the same discriminator.
Set<String> visitedSchemasCopy = new TreeSet<>(visitedSchemas);
CodegenProperty thisCp = discriminatorFound(oneOfSchema.getName(), oneOfSchema, discPropName, visitedSchemasCopy);
if (thisCp == null) {
once(LOGGER).warn(
"'{}' defines discriminator '{}', but the referenced OneOf schema '{}' is missing {}",
composedSchemaName, discPropName, modelName, discPropName);
}
if (cp != null && cp.dataType == null) {
cp = thisCp;
continue;
}
if (cp != thisCp) {
once(LOGGER).warn(
"'{}' 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",
composedSchemaName, discPropName, modelName, discPropName, discPropName);
}
}
return cp;
}
if (ModelUtils.hasAnyOf(composedSchema)) {
// All anyOf definitions must contain the discriminator because a min of one must be selected
CodegenProperty cp = new CodegenProperty();
for (Object anyOf : composedSchema.getAnyOf()) {
Schema anyOfSchema = (Schema) anyOf;
String modelName = ModelUtils.getSimpleRef(anyOfSchema.get$ref());
// Must use a copied set as the anyOf schemas can point to the same discriminator.
Set<String> visitedSchemasCopy = new TreeSet<>(visitedSchemas);
CodegenProperty thisCp = discriminatorFound(anyOfSchema.getName(), anyOfSchema, discPropName, visitedSchemasCopy);
if (thisCp == null) {
once(LOGGER).warn(
"'{}' defines discriminator '{}', but the referenced AnyOf schema '{}' is missing {}",
composedSchemaName, discPropName, modelName, discPropName);
}
if (cp != null && cp.dataType == null) {
cp = thisCp;
continue;
}
if (cp != thisCp) {
once(LOGGER).warn(
"'{}' 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",
composedSchemaName, discPropName, modelName, discPropName, discPropName);
}
}
return cp;

}
}
return null;
}

/**
* Recursively look in Schema sc for the discriminator and return it
*
Expand Down Expand Up @@ -3495,7 +3391,7 @@ protected List<MappedModel> getOneOfAnyOfDescendants(String composedSchemaName,
"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",
composedSchemaName);
}
CodegenProperty df = discriminatorFound(composedSchemaName, sc, discPropName, new TreeSet<String>());
CodegenProperty df = DiscriminatorUtils.discriminatorFound(openAPI, composedSchemaName, sc, discPropName, new TreeSet<String>());
String modelName = ModelUtils.getSimpleRef(ref);
if (df == null || !df.isString || !df.required) {
String msgSuffix = "";
Expand Down Expand Up @@ -3611,7 +3507,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch

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

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

/**
* Get the property type for the discriminator
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Discriminator;
import io.swagger.v3.oas.models.media.Schema;
import org.openapitools.codegen.CodegenProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,6 +17,91 @@ public class DiscriminatorUtils {

private static final String CONFLICTING_DISCRIMINATOR_NAMES =
"The alternative schemas have conflicting discriminator property names. The schemas must have the same property name, but found {}";
private static final String DEFINES_DISCRIMINATOR_BUT_REFERENCE_ALTERNATIVE_IS_MISSING =
"'{}' defines discriminator '{}', but the referenced schema '{}' is missing {}";
private static final String DEFINES_DISCRIMINATOR_BUT_ALTERNATIVE_HAS_OTHER_DEFINITION =
"'{}' defines discriminator '{}', but the schema '{}' has a different {} definition than the prior schema's. Make sure the {} type and required values are the same";

/**
* Recursively look in Schema sc for the discriminator discPropName
* and return a CodegenProperty with the dataType and required params set
* the returned CodegenProperty may not be required, and it may not be of type string
*
* @param openAPI The openAPI specification
* @param composedSchemaName The name of the sc Schema
* @param sc The Schema that may contain the discriminator
* @param discPropName The String that is the discriminator propertyName in the schema
* @param visitedSchemas A set of visited schema names
*/
public static CodegenProperty discriminatorFound(OpenAPI openAPI,
String composedSchemaName,
Schema sc,
String discPropName,
Set<String> visitedSchemas) {
Schema refSchema = ModelUtils.getReferencedSchema(openAPI, sc);
String schemaName = Optional.ofNullable(composedSchemaName)
.or(() -> Optional.ofNullable(refSchema.getName()))
.or(() -> Optional.ofNullable(sc.get$ref()).map(ModelUtils::getSimpleRef))
.orElseGet(sc::toString);
if (visitedSchemas.contains(schemaName)) { // recursive schema definition found
return null;
} else {
visitedSchemas.add(schemaName);
}

if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) {
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, getDiscriminatorSchema(refSchema, discPropName));
CodegenProperty cp = new CodegenProperty();
Comment thread
Mattias-Sehlstedt marked this conversation as resolved.
if (ModelUtils.isStringSchema(discSchema)) {
cp.isString = true;
}
cp.setRequired(false);
if (refSchema.getRequired() != null && refSchema.getRequired().contains(discPropName)) {
cp.setRequired(true);
}
cp.setIsEnum(discSchema.getEnum() != null && !discSchema.getEnum().isEmpty());
return cp;
}
if (ModelUtils.isComposedSchema(refSchema)) {
Schema composedSchema = refSchema;
if (composedSchema.getAllOf() != null) {
// If our discriminator is in one of the allOf schemas break when we find it
for (Object allOf : composedSchema.getAllOf()) {
Schema allOfSchema = (Schema) allOf;
CodegenProperty cp = discriminatorFound(openAPI, allOfSchema.getName(), allOfSchema, discPropName, visitedSchemas);
if (cp != null) {
return cp;
}
}
}
if (ModelUtils.hasOneOf(composedSchema)) {
// All oneOf definitions must contain the discriminator
CodegenProperty cp = new CodegenProperty();
for (Object oneOf : composedSchema.getOneOf()) {
Schema oneOfSchema = (Schema) oneOf;
CodegenProperty discCP = getDiscriminatorCodegenProperty(openAPI, cp, composedSchemaName, oneOfSchema, discPropName, visitedSchemas);
if (discCP != null) {
cp = discCP;
}
}
return cp;
}
if (ModelUtils.hasAnyOf(composedSchema)) {
// All anyOf definitions must contain the discriminator because a min of one must be selected
CodegenProperty cp = new CodegenProperty();
for (Object anyOf : composedSchema.getAnyOf()) {
Schema anyOfSchema = (Schema) anyOf;
CodegenProperty discCP = getDiscriminatorCodegenProperty(openAPI, cp, composedSchemaName, anyOfSchema, discPropName, visitedSchemas);
if (discCP != null) {
cp = discCP;
}
}
return cp;

}
}
return null;
}

/**
* Gets the simple ref name of the discriminator property type from the schema.
Expand All @@ -30,25 +116,6 @@ public static Optional<String> getDiscriminatorPropertyType(Schema schema, Strin
.map(ModelUtils::getSimpleRef);
}

/**
* Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
* An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
* referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
*
* @param schema The input OAS schema.
* @param discriminatorName The name of the discriminator property.
*/
public static Schema getDiscriminatorSchema(Schema schema, String discriminatorName) {
if (schema.getProperties() == null) {
return null;
}
Schema discSchema = (Schema) schema.getProperties().get(discriminatorName);
if (ModelUtils.isAllOf(discSchema)) {
discSchema = (Schema) discSchema.getAllOf().get(0);
}
return discSchema;
}

/**
* Recursively look in Schema sc for the discriminator and return it
*
Expand Down Expand Up @@ -106,6 +173,25 @@ public static Discriminator recursiveGetDiscriminator(
return null;
}

/**
* Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
* An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
* referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
*
* @param schema The input OAS schema.
* @param discriminatorName The name of the discriminator property.
*/
private static Schema getDiscriminatorSchema(Schema schema, String discriminatorName) {
if (schema.getProperties() == null) {
return null;
}
Schema discSchema = (Schema) schema.getProperties().get(discriminatorName);
if (ModelUtils.isAllOf(discSchema)) {
discSchema = (Schema) discSchema.getAllOf().get(0);
}
return discSchema;
}

/**
* Check whether the alternative schemas share a discriminator, and if they do, return it
*
Expand Down Expand Up @@ -151,4 +237,38 @@ private static Discriminator getDiscriminatorFromAlternatives(
return null;
}

/**
* Recursively look in schema for the discriminator discPropName
*
* @param openAPI The openAPI specification
* @param cp Any previously calculated discriminator codegen property
* @param composedSchemaName The name of the sc Schema
* @param schema The Schema that may contain the discriminator
* @param discPropName The String that is the discriminator propertyName in the schema
* @param visitedSchemas A set of visited schema names
*/
private static CodegenProperty getDiscriminatorCodegenProperty(OpenAPI openAPI,
CodegenProperty cp,
String composedSchemaName,
Schema schema,
String discPropName,
Set<String> visitedSchemas) {
String modelName = ModelUtils.getSimpleRef(schema.get$ref());
// Must use a copied set as the alternative schemas can point to the same discriminator.
Set<String> visitedSchemasCopy = new TreeSet<>(visitedSchemas);
CodegenProperty thisCp = discriminatorFound(openAPI, schema.getName(), schema, discPropName, visitedSchemasCopy);
if (thisCp == null) {
once(LOGGER).warn(DEFINES_DISCRIMINATOR_BUT_REFERENCE_ALTERNATIVE_IS_MISSING,
composedSchemaName, discPropName, modelName, discPropName);
}
if (cp != null && cp.dataType == null) {
return thisCp;
}
if (cp != thisCp) {
once(LOGGER).warn(DEFINES_DISCRIMINATOR_BUT_ALTERNATIVE_HAS_OTHER_DEFINITION,
composedSchemaName, discPropName, modelName, discPropName, discPropName);
}
return null;
}

}
Loading