diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index a1f0fe6246de..64c890910f22 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -2515,7 +2515,7 @@ private String getPrimitiveType(Schema schema) { // Note: the value of a free-form object cannot be an arbitrary type. Per OAS specification, // it must be a map of string to values. return "object"; - } else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { // having property implies it's a model + } else if (ModelUtils.hasProperties(schema)) { // having property implies it's a model return "object"; } else if (ModelUtils.isAnyType(schema)) { return "AnyType"; @@ -2707,8 +2707,8 @@ protected void updateModelForComposedSchema(CodegenModel m, Schema schema, Map allRequired = new ArrayList<>(); // if schema has properties outside of allOf/oneOf/anyOf also add them to m - if (composed.getProperties() != null && !composed.getProperties().isEmpty()) { - if (composed.getOneOf() != null && !composed.getOneOf().isEmpty()) { + if (ModelUtils.hasProperties(composed)) { + if (ModelUtils.hasOneOf(composed)) { LOGGER.warn("'oneOf' is intended to include only the additional optional OAS extension discriminator object. " + "For more details, see https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.9.2.1.3 and the OAS section on 'Composition and Inheritance'."); } @@ -3362,7 +3362,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, } } } - if (composedSchema.getOneOf() != null && composedSchema.getOneOf().size() != 0) { + if (ModelUtils.hasOneOf(composedSchema)) { // All oneOf definitions must contain the discriminator CodegenProperty cp = new CodegenProperty(); for (Object oneOf : composedSchema.getOneOf()) { @@ -3388,7 +3388,7 @@ private CodegenProperty discriminatorFound(String composedSchemaName, Schema sc, } return cp; } - if (composedSchema.getAnyOf() != null && composedSchema.getAnyOf().size() != 0) { + 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()) { @@ -3457,7 +3457,7 @@ private Discriminator recursiveGetDiscriminator(Schema sc, ArrayList vis } } } - if (composedSchema.getOneOf() != null && composedSchema.getOneOf().size() != 0) { + if (ModelUtils.hasOneOf(composedSchema)) { // All oneOf definitions must contain the discriminator Integer hasDiscriminatorCnt = 0; Integer hasNullTypeCnt = 0; @@ -3792,7 +3792,7 @@ protected void addProperties(Map properties, List requir } if (ModelUtils.isComposedSchema(schema)) { // fix issue #16797 and #15796, constructor fail by missing parent required params - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (ModelUtils.hasProperties(schema)) { properties.putAll(schema.getProperties()); } @@ -8599,7 +8599,7 @@ public void setRemoveEnumValuePrefix(final boolean removeEnumValuePrefix) { * @param name name of the parent oneOf schema */ public void addOneOfNameExtension(Schema schema, String name) { - if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + if (ModelUtils.hasOneOf(schema)) { schema.addExtension(X_ONE_OF_NAME, name); } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java index 777fed9b2cb4..f9e1aef7f75e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java @@ -30,7 +30,6 @@ import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; @@ -236,9 +235,9 @@ private boolean isModelNeeded(Schema schema, Set visitedSchemas) { if (resolveInlineEnums && schema.getEnum() != null && schema.getEnum().size() > 0) { return true; } - if (schema.getType() == null || "object".equals(schema.getType())) { + if (schema.getType() == null || ModelUtils.isObjectTypeOAS30(schema)) { // object or undeclared type with properties - if (schema.getProperties() != null && schema.getProperties().size() > 0) { + if (ModelUtils.hasProperties(schema)) { return true; } } @@ -264,7 +263,7 @@ private boolean isModelNeeded(Schema schema, Set visitedSchemas) { return isModelNeeded((Schema) schema.getAllOf().get(0), visitedSchemas); } - if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) { + if (ModelUtils.hasAllOf(schema)) { // check to ensure at least one of the allOf item is model for (Object inner : schema.getAllOf()) { if (isModelNeeded(ModelUtils.getReferencedSchema(openAPI, (Schema) inner), visitedSchemas)) { @@ -275,10 +274,10 @@ private boolean isModelNeeded(Schema schema, Set visitedSchemas) { return false; } - if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) { + if (ModelUtils.hasAnyOf(schema)) { return true; } - if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + if (ModelUtils.hasOneOf(schema)) { return true; } } @@ -297,9 +296,9 @@ private void gatherInlineModels(Schema schema, String modelPrefix) { if (schema.get$ref() != null) { // if ref already, no inline schemas should be present but check for // any to catch OpenAPI violations - if (isModelNeeded(schema) || "object".equals(schema.getType()) || + if (isModelNeeded(schema) || ModelUtils.isObjectTypeOAS30(schema) || schema.getProperties() != null || schema.getAdditionalProperties() != null || - ModelUtils.isComposedSchema(schema)) { + ModelUtils.isComposedSchema(schema)) { LOGGER.error("Illegal schema found with $ref combined with other properties," + " no properties should be defined alongside a $ref:\n " + schema.toString()); } @@ -308,7 +307,7 @@ private void gatherInlineModels(Schema schema, String modelPrefix) { // Check object models / any type models / composed models for properties, // if the schema has a type defined that is not "object" it should not define // any properties - if (schema.getType() == null || "object".equals(schema.getType())) { + if (schema.getType() == null || ModelUtils.isObjectTypeOAS30(schema)) { // Check properties and recurse, each property could be its own inline model Map props = schema.getProperties(); if (props != null) { @@ -640,10 +639,8 @@ private void flattenComposedChildren(String key, List children, boolean ListIterator listIterator = children.listIterator(); while (listIterator.hasNext()) { Schema component = listIterator.next(); - if ((component != null) && - (component.get$ref() == null) && - ((component.getProperties() != null && !component.getProperties().isEmpty()) || - (component.getEnum() != null && !component.getEnum().isEmpty()))) { + boolean componentDoesNotHaveRef = component != null && component.get$ref() == null; + if (componentDoesNotHaveRef && (ModelUtils.hasProperties(component) || ModelUtils.hasEnum(component))) { // If a `title` attribute is defined in the inline schema, codegen uses it to name the // inline schema. Otherwise, we'll use the default naming such as InlineObject1, etc. // We know that this is not the best way to name the model. @@ -839,7 +836,7 @@ private void flattenProperties(OpenAPI openAPI, Map properties, Schema inner = ModelUtils.getSchemaItems(property); if (ModelUtils.isObjectSchema(inner)) { Schema op = inner; - if (op.getProperties() != null && op.getProperties().size() > 0) { + if (ModelUtils.hasProperties(op)) { flattenProperties(openAPI, op.getProperties(), path); String modelName = resolveModelName(op.getTitle(), path + "_" + key); Schema innerModel = modelFromProperty(openAPI, op, modelName); @@ -869,7 +866,7 @@ private void flattenProperties(OpenAPI openAPI, Map properties, Schema inner = ModelUtils.getAdditionalProperties(property); if (ModelUtils.isObjectSchema(inner)) { Schema op = inner; - if (op.getProperties() != null && op.getProperties().size() > 0) { + if (ModelUtils.hasProperties(op)) { flattenProperties(openAPI, op.getProperties(), path); String modelName = resolveModelName(op.getTitle(), path + "_" + key); Schema innerModel = modelFromProperty(openAPI, op, modelName); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index 95f793c195da..028a48ea91c3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -760,19 +760,19 @@ public Schema normalizeSchema(Schema schema, Set visitedSchemas) { schema = normalizeComplexComposedSchema(schema, visitedSchemas); } - if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) { + if (ModelUtils.hasAllOf(schema)) { return normalizeAllOf(schema, visitedSchemas); } - if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + if (ModelUtils.hasOneOf(schema)) { return normalizeOneOf(schema, visitedSchemas); } - if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) { + if (ModelUtils.hasAnyOf(schema)) { return normalizeAnyOf(schema, visitedSchemas); } - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (ModelUtils.hasProperties(schema)) { normalizeProperties(schema, visitedSchemas); } @@ -781,7 +781,7 @@ public Schema normalizeSchema(Schema schema, Set visitedSchemas) { } return schema; - } else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + } else if (ModelUtils.hasProperties(schema)) { normalizeProperties(schema, visitedSchemas); } else if (schema.getAdditionalProperties() instanceof Schema) { // map normalizeMapSchema(schema); @@ -1109,7 +1109,7 @@ protected Schema normalizeAnyOf(Schema schema, Set visitedSchemas) { protected Schema normalizeComplexComposedSchema(Schema schema, Set visitedSchemas) { // loop through properties, if any - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (ModelUtils.hasProperties(schema)) { normalizeProperties(schema, visitedSchemas); } @@ -1294,10 +1294,9 @@ protected void processRemoveAnyOfOneOfAndKeepPropertiesOnly(Schema schema) { return; } - if (((schema.getOneOf() != null && !schema.getOneOf().isEmpty()) - || (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty())) // has anyOf or oneOf - && (schema.getProperties() != null && !schema.getProperties().isEmpty()) // has properties - && schema.getAllOf() == null) { // not allOf + boolean hasAnyOfOrOneOf = ModelUtils.hasOneOf(schema) || ModelUtils.hasAnyOf(schema); + boolean notAllOf = schema.getAllOf() == null; + if (hasAnyOfOrOneOf && ModelUtils.hasProperties(schema) && notAllOf) { // clear oneOf, anyOf schema.setOneOf(null); schema.setAnyOf(null); @@ -1374,9 +1373,7 @@ protected Schema processSimplifyAnyOfEnum(Schema schema) { if (schema.getAnyOf() == null || schema.getAnyOf().isEmpty()) { return schema; } - if(schema.getOneOf() != null && !schema.getOneOf().isEmpty() || - schema.getAllOf() != null && !schema.getAllOf().isEmpty() || - schema.getNot() != null) { + if(ModelUtils.hasOneOf(schema) || ModelUtils.hasAllOf(schema) || schema.getNot() != null) { //only convert to enum if anyOf is the only composition return schema; } @@ -1399,9 +1396,7 @@ protected Schema processSimplifyOneOfEnum(Schema schema) { if (schema.getOneOf() == null || schema.getOneOf().isEmpty()) { return schema; } - if(schema.getAnyOf() != null && !schema.getAnyOf().isEmpty() || - schema.getAllOf() != null && !schema.getAllOf().isEmpty() || - schema.getNot() != null) { + if(ModelUtils.hasAnyOf(schema) || ModelUtils.hasAllOf(schema) || schema.getNot() != null) { //only convert to enum if oneOf is the only composition return schema; } @@ -2109,7 +2104,7 @@ protected void processNormalizeOtherThanObjectWithProperties(Schema schema) { // Check object models / any type models / composed models for properties, // if the schema has a type defined that is not "object" it should not define // any properties - if (schema.getType() != null && !"object".equals(schema.getType())) { + if (schema.getType() != null && !ModelUtils.isObjectTypeOAS30(schema)) { schema.setProperties(null); } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java index 3310eaf09934..874b28d0bcca 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java @@ -1383,7 +1383,7 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) { } return toArrayDefaultValue(cp, schema); } else if (ModelUtils.isMapSchema(schema) && !(ModelUtils.isComposedSchema(schema))) { - if (schema.getProperties() != null && schema.getProperties().size() > 0) { + if (ModelUtils.hasProperties(schema)) { // object is complex object with free-form additional properties if (schema.getDefault() != null) { return super.toDefaultValue(schema); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java index 1c0bab00c064..3a799390a213 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java @@ -406,7 +406,7 @@ public String getSchemaType(Schema p) { openAPIType = "UNKNOWN_OPENAPI_TYPE"; } - if ((p.getAnyOf() != null && !p.getAnyOf().isEmpty()) || (p.getOneOf() != null && !p.getOneOf().isEmpty())) { + if (ModelUtils.hasAnyOf(p) || ModelUtils.hasOneOf(p)) { return openAPIType; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java index a4c775057c47..4e246c7adadb 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java @@ -512,7 +512,7 @@ private String toExampleValueRecursive(Schema schema, List includedSchem // if required and optionals List reqs = new ArrayList<>(); - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (ModelUtils.hasProperties(schema)) { for (Object toAdd : schema.getProperties().keySet()) { reqs.add((String) toAdd); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonPydanticV1Codegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonPydanticV1Codegen.java index 7591c1df7c37..4d6c2e9713ea 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonPydanticV1Codegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonPydanticV1Codegen.java @@ -483,7 +483,7 @@ private String toExampleValueRecursive(Schema schema, List includedSchem // if required and optionals List reqs = new ArrayList<>(); - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (ModelUtils.hasProperties(schema)) { for (Object toAdd : schema.getProperties().keySet()) { reqs.add((String) toAdd); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java index 1056c8b30eb7..4a1b4f4b86b8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppHttplibServerCodegen.java @@ -980,7 +980,7 @@ private void processNestedSchemas(Schema schema, String parentName, int depth) { // Set title for nested inline schemas if (propSchema.getTitle() == null && propSchema.get$ref() == null) { // For nested objects, create a meaningful name - if ("object".equals(propSchema.getType()) || (propSchema.getType() == null && propSchema.getProperties() != null)) { + if (isNestedObject(propSchema)) { String title = toPascalCase(parentName + "_" + propertyName); propSchema.setTitle(title); @@ -995,7 +995,7 @@ private void processNestedSchemas(Schema schema, String parentName, int depth) { if (schema.getItems() != null) { Schema itemSchema = schema.getItems(); if (itemSchema.getTitle() == null && itemSchema.get$ref() == null) { - if ("object".equals(itemSchema.getType()) || (itemSchema.getType() == null && itemSchema.getProperties() != null)) { + if (isNestedObject(itemSchema)) { String title = toPascalCase(parentName + "_item"); itemSchema.setTitle(title); processNestedSchemas(itemSchema, title, depth + 1); @@ -1007,7 +1007,7 @@ private void processNestedSchemas(Schema schema, String parentName, int depth) { if (schema.getAdditionalProperties() instanceof Schema) { Schema additionalSchema = (Schema) schema.getAdditionalProperties(); if (additionalSchema.getTitle() == null && additionalSchema.get$ref() == null) { - if ("object".equals(additionalSchema.getType()) || (additionalSchema.getType() == null && additionalSchema.getProperties() != null)) { + if (isNestedObject(additionalSchema)) { String title = toPascalCase(parentName + "_additional"); additionalSchema.setTitle(title); processNestedSchemas(additionalSchema, title, depth + 1); @@ -1499,7 +1499,7 @@ public String toApiFilename(String name) { @Override @SuppressWarnings({"rawtypes", "unchecked"}) public String getTypeDeclaration(Schema p) { - if (p.getOneOf() != null && !p.getOneOf().isEmpty()) { + if (ModelUtils.hasOneOf(p)) { // For oneOf, map to std::variant of possible types StringBuilder variant = new StringBuilder("std::variant<"); List schemas = p.getOneOf(); @@ -1509,7 +1509,7 @@ public String getTypeDeclaration(Schema p) { } variant.append(">"); return variant.toString(); - } else if (p.getAnyOf() != null && !p.getAnyOf().isEmpty()) { + } else if (ModelUtils.hasAnyOf(p)) { // For anyOf, also use std::variant to handle multiple possible types StringBuilder variant = new StringBuilder("std::variant<"); List schemas = p.getAnyOf(); @@ -1557,7 +1557,7 @@ public CodegenModel fromModel(String name, Schema schema) { model.name = toModelName(modelName); model.classname = model.name; - if (schema.getAllOf() != null && !schema.getAllOf().isEmpty() && this.openAPI != null) { + if (ModelUtils.hasAllOf(schema) && this.openAPI != null) { int refCount = 0; String parentRef = null; Set parentPropertyNames = new HashSet<>(); @@ -1619,7 +1619,7 @@ else if (refCount > 1 || mergedVars.size() > 0) { } // Handle oneOf/anyOf schemas - generate std::variant type alias instead of class - if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + if (ModelUtils.hasOneOf(schema)) { model.vendorExtensions.put("isOneOfSchema", true); model.vendorExtensions.put("hasVariant", true); List variantTypes = new ArrayList<>(); @@ -1647,7 +1647,7 @@ else if (refCount > 1 || mergedVars.size() > 0) { model.vendorExtensions.put("discriminatorMapping", mappingList); } } - } else if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) { + } else if (ModelUtils.hasAnyOf(schema)) { model.vendorExtensions.put("isAnyOfSchema", true); model.vendorExtensions.put("hasVariant", true); List variantTypes = new ArrayList<>(); @@ -2570,4 +2570,8 @@ public Map postProcessSupportingFileData(Map obj } return super.postProcessSupportingFileData(objs); } + + private static boolean isNestedObject(Schema schema) { + return ModelUtils.isObjectTypeOAS30(schema) || (schema.getType() == null && schema.getProperties() != null); + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestSdkClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestSdkClientCodegen.java index 5a8e523cf513..ef9b68de1b95 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestSdkClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestSdkClientCodegen.java @@ -293,7 +293,7 @@ public CodegenModel fromModel(String name, Schema model) { // Handle additionalProperties for models that have both properties and additionalProperties Schema addlProps = ModelUtils.getAdditionalProperties(model); - if (addlProps != null && model.getProperties() != null && !model.getProperties().isEmpty()) { + if (addlProps != null && ModelUtils.hasProperties(model)) { // This model has both defined properties AND additionalProperties codegenModel.additionalPropertiesType = getTypeDeclaration(addlProps); // Add import for web::json::value which is used to store additional properties diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index 84d8cf484f73..ad002afbcd33 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -410,6 +410,25 @@ public static String getSimpleRef(String ref) { return ref; } + public static boolean hasProperties(Schema schema) { + return schema.getProperties() != null && !schema.getProperties().isEmpty(); + } + + public static boolean hasEnum(Schema schema) { + return schema.getEnum() != null && !schema.getEnum().isEmpty(); + } + + /** + * Return true if the specified schema is type object + * Only considers OAS 3.0 {@code type} and not OAS 3.1 {@code types} + * + * @param schema the OAS schema + * @return true if the specified schema is an OAS 3.0 {@code object} schema. + */ + public static boolean isObjectTypeOAS30(Schema schema) { + return SchemaTypeUtil.OBJECT_TYPE.equals(schema.getType()); + } + /** * Return true if the specified schema is type object * We can't use isObjectSchema because it requires properties to exist which is not required @@ -453,7 +472,7 @@ public static boolean isObjectSchema(Schema schema) { // must not be a map (SchemaTypeUtil.OBJECT_TYPE.equals(getType(schema)) && !(ModelUtils.isMapSchema(schema))) || // must have at least one property - (getType(schema) == null && schema.getProperties() != null && !schema.getProperties().isEmpty()); + (getType(schema) == null && hasProperties(schema)); } /** @@ -502,19 +521,19 @@ public static boolean isComposedSchema(Schema schema) { public static boolean isComplexComposedSchema(Schema schema) { int count = 0; - if (schema.getAllOf() != null && !schema.getAllOf().isEmpty()) { + if (hasAllOf(schema)) { count++; } - if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { + if (hasOneOf(schema)) { count++; } - if (schema.getAnyOf() != null && !schema.getAnyOf().isEmpty()) { + if (hasAnyOf(schema)) { count++; } - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + if (hasProperties(schema)) { count++; } @@ -884,7 +903,7 @@ public static boolean isFreeFormObject(Schema schema, OpenAPI openAPI) { return false; } - if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { // has properties + if (hasProperties(schema)) { return false; } @@ -921,7 +940,7 @@ public static boolean isFreeFormObject(Schema schema, OpenAPI openAPI) { if (schema.getExtensions() != null && schema.getExtensions().containsKey(freeFormExplicit)) { // User has hard-coded vendor extension to handle free-form evaluation. boolean isFreeFormExplicit = Boolean.parseBoolean(String.valueOf(schema.getExtensions().get(freeFormExplicit))); - if (!isFreeFormExplicit && addlProps != null && addlProps.getProperties() != null && !addlProps.getProperties().isEmpty()) { + if (!isFreeFormExplicit && addlProps != null && hasProperties(addlProps)) { once(LOGGER).error(String.format(Locale.ROOT, "Potentially confusing usage of %s within model which defines additional properties", freeFormExplicit)); } return isFreeFormExplicit; @@ -1334,7 +1353,7 @@ public static boolean hasSelfReference(OpenAPI openAPI, } } else if (schema.getNot() != null) { return hasSelfReference(openAPI, schema.getNot(), visitedSchemaNames); - } else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) { + } else if (hasProperties(schema)) { // go through properties to see if there's any self-reference for (Schema property : ((Map) schema.getProperties()).values()) { if (hasSelfReference(openAPI, property, visitedSchemaNames)) { @@ -1400,7 +1419,7 @@ public static Schema unaliasSchema(OpenAPI openAPI, } else if (isComposedSchema(ref)) { return schema; } else if (isMapSchema(ref)) { - if (ref.getProperties() != null && !ref.getProperties().isEmpty()) // has at least one property + if (hasProperties(ref)) return schema; // treat it as model else { if (isGenerateAliasAsModel(ref)) { @@ -1412,7 +1431,7 @@ public static Schema unaliasSchema(OpenAPI openAPI, } } } else if (isObjectSchema(ref)) { // model - if (ref.getProperties() != null && !ref.getProperties().isEmpty()) { // has at least one property + if (hasProperties(ref)) { // TODO we may need to check `hasSelfReference(openAPI, ref)` as a special/edge case: // TODO we may also need to revise below to return `ref` instead of schema // which is the last reference to the actual model/object @@ -1530,11 +1549,11 @@ public static Map> getChildrenMap(OpenAPI openAPI) { * @return a list of schema defined in allOf, anyOf or oneOf */ public static List getInterfaces(Schema composed) { - if (composed.getAllOf() != null && !composed.getAllOf().isEmpty()) { + if (hasAllOf(composed)) { return composed.getAllOf(); - } else if (composed.getAnyOf() != null && !composed.getAnyOf().isEmpty()) { + } else if (hasAnyOf(composed)) { return composed.getAnyOf(); - } else if (composed.getOneOf() != null && !composed.getOneOf().isEmpty()) { + } else if (hasOneOf(composed)) { return composed.getOneOf(); } else { return Collections.emptyList(); @@ -2112,7 +2131,7 @@ public static boolean hasAllOf(Schema schema) { * @return true if the schema contains allOf but no properties/oneOf/anyOf defined. */ public static boolean isAllOfWithProperties(Schema schema) { - return hasAllOf(schema) && (schema.getProperties() != null && !schema.getProperties().isEmpty()) && + return hasAllOf(schema) && (hasProperties(schema)) && (schema.getOneOf() == null || schema.getOneOf().isEmpty()) && (schema.getAnyOf() == null || schema.getAnyOf().isEmpty()); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java index 1c2a68ef4e09..b47d0d6e16fc 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/validations/oas/OpenApiSchemaValidations.java @@ -67,8 +67,8 @@ private static ValidationRule.Result checkOneOfWithProperties(SchemaWrapper sche // check for loosely defined oneOf extension requirements. // This is a recommendation because the 3.0.x spec is not clear enough on usage of oneOf. // see https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.9.2.1.3 and the OAS section on 'Composition and Inheritance'. - if (schema.getOneOf() != null && schema.getOneOf().size() > 0) { - if (schema.getProperties() != null && schema.getProperties().size() >= 1 && schema.getProperties().get("discriminator") == null) { + if (ModelUtils.hasOneOf(schema)) { + if (ModelUtils.hasProperties(schema) && schema.getProperties().get("discriminator") == null) { // not necessarily "invalid" here, but we trigger the recommendation which requires the method to return false. result = ValidationRule.Fail.empty(); }