From 36d366b19b6f135fbbff050b957946ab66aef5b5 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Mon, 7 Dec 2020 23:09:05 +0800 Subject: [PATCH] refactor isAnyTypeSchema, isFreeFormType --- .../openapitools/codegen/DefaultCodegen.java | 92 ++----------------- .../codegen/languages/AbstractGoCodegen.java | 3 +- .../languages/CppRestSdkClientCodegen.java | 2 +- .../languages/PythonClientCodegen.java | 6 +- .../codegen/utils/ModelUtils.java | 42 +++++++++ 5 files changed, 56 insertions(+), 89 deletions(-) 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 9bd33ffcf55..5b5d8b69059 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 @@ -2069,13 +2069,13 @@ public class DefaultCodegen implements CodegenConfig { return schema.getFormat(); } return "string"; - } else if (isFreeFormObject(schema)) { + } else if (ModelUtils.isFreeFormObject(openAPI, 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 return "object"; - } else if (isAnyTypeSchema(schema)) { + } else if (ModelUtils.isAnyTypeSchema(openAPI, schema)) { return "AnyType"; } else if (StringUtils.isNotEmpty(schema.getType())) { if (!importMapping.containsKey(schema.getType())) { @@ -2284,7 +2284,7 @@ public class DefaultCodegen implements CodegenConfig { m.xmlNamespace = schema.getXml().getNamespace(); m.xmlName = schema.getXml().getName(); } - if (isAnyTypeSchema(schema)) { + if (ModelUtils.isAnyTypeSchema(openAPI, schema)) { // The 'null' value is allowed when the OAS schema is 'any type'. // See https://github.com/OAI/OpenAPI-Specification/issues/1389 if (Boolean.FALSE.equals(schema.getNullable())) { @@ -3251,9 +3251,9 @@ public class DefaultCodegen implements CodegenConfig { property.hasValidation = true; } - } else if (isFreeFormObject(p)) { + } else if (ModelUtils.isFreeFormObject(openAPI, p)) { property.isFreeFormObject = true; - } else if (isAnyTypeSchema(p)) { + } else if (ModelUtils.isAnyTypeSchema(openAPI, p)) { // The 'null' value is allowed when the OAS schema is 'any type'. // See https://github.com/OAI/OpenAPI-Specification/issues/1389 if (Boolean.FALSE.equals(p.getNullable())) { @@ -3366,13 +3366,13 @@ public class DefaultCodegen implements CodegenConfig { } CodegenProperty cp = fromProperty("inner", innerSchema); updatePropertyForMap(property, cp); - } else if (isFreeFormObject(p)) { + } else if (ModelUtils.isFreeFormObject(openAPI, p)) { property.isFreeFormObject = true; property.baseType = getSchemaType(p); if (languageSpecificPrimitives.contains(property.dataType)) { property.isPrimitiveType = true; } - } else if (isAnyTypeSchema(p)) { + } else if (ModelUtils.isAnyTypeSchema(openAPI, p)) { property.isAnyType = true; property.baseType = getSchemaType(p); if (languageSpecificPrimitives.contains(property.dataType)) { @@ -6108,7 +6108,7 @@ public class DefaultCodegen implements CodegenConfig { codegenProperty = codegenProperty.items; } } - } else if (isFreeFormObject(schema)) { + } else if (ModelUtils.isFreeFormObject(openAPI, schema)) { // HTTP request body is free form object CodegenProperty codegenProperty = fromProperty("FREE_FORM_REQUEST_BODY", schema); if (codegenProperty != null) { @@ -6545,82 +6545,6 @@ public class DefaultCodegen implements CodegenConfig { } } - /** - * Return true if the schema value can be any type, i.e. it can be - * the null value, integer, number, string, object or array. - * One use case is when the "type" attribute in the OAS schema is unspecified. - * - * Examples: - * - * arbitraryTypeValue: - * description: This is an arbitrary type schema. - * It is not a free-form object. - * The value can be any type except the 'null' value. - * arbitraryTypeNullableValue: - * description: This is an arbitrary type schema. - * It is not a free-form object. - * The value can be any type, including the 'null' value. - * nullable: true - * - * @param schema the OAS schema. - * @return true if the schema value can be an arbitrary type. - */ - public boolean isAnyTypeSchema(Schema schema) { - if (schema == null) { - once(LOGGER).error("Schema cannot be null in isAnyTypeSchema check"); - return false; - } - - if (isFreeFormObject(schema)) { - // make sure it's not free form object - return false; - } - - if (schema.getClass().equals(Schema.class) && schema.get$ref() == null && schema.getType() == null && - (schema.getProperties() == null || schema.getProperties().isEmpty()) && - schema.getAdditionalProperties() == null && schema.getNot() == null && - schema.getEnum() == null) { - return true; - // If and when type arrays are supported in a future OAS specification, - // we could return true if the type array includes all possible JSON schema types. - } - return false; - } - - /** - * Check to see if the schema is a free form object. - * - * A free form object is an object (i.e. 'type: object' in a OAS document) that: - * 1) Does not define properties, and - * 2) Is not a composed schema (no anyOf, oneOf, allOf), and - * 3) additionalproperties is not defined, or additionalproperties: true, or additionalproperties: {}. - * - * Examples: - * - * components: - * schemas: - * arbitraryObject: - * type: object - * description: This is a free-form object. - * The value must be a map of strings to values. The value cannot be 'null'. - * It cannot be array, string, integer, number. - * arbitraryNullableObject: - * type: object - * description: This is a free-form object. - * The value must be a map of strings to values. The value can be 'null', - * It cannot be array, string, integer, number. - * nullable: true - * arbitraryTypeValue: - * description: This is NOT a free-form object. - * The value can be any type except the 'null' value. - * - * @param schema potentially containing a '$ref' - * @return true if it's a free-form object - */ - protected boolean isFreeFormObject(Schema schema) { - return ModelUtils.isFreeFormObject(this.openAPI, schema); - } - /** * Returns the additionalProperties Schema for the specified input schema. * diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java index 694f53281ed..d9eff4ad3be 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractGoCodegen.java @@ -17,6 +17,7 @@ package org.openapitools.codegen.languages; +import com.sun.org.apache.xpath.internal.operations.Mod; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; import org.apache.commons.io.FilenameUtils; @@ -394,7 +395,7 @@ public abstract class AbstractGoCodegen extends DefaultCodegen implements Codege if (ref != null && !ref.isEmpty()) { type = openAPIType; - } else if ("object".equals(openAPIType) && isAnyTypeSchema(p)) { + } else if ("object".equals(openAPIType) && ModelUtils.isAnyTypeSchema(openAPI, p)) { // Arbitrary type. Note this is not the same thing as free-form object. type = "interface{}"; } else if (typeMapping.containsKey(openAPIType)) { 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 8dd888dd7db..72605513a34 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 @@ -395,7 +395,7 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen { return "new " + toModelName(ModelUtils.getSimpleRef(p.get$ref())) + "()"; } else if (ModelUtils.isStringSchema(p)) { return "utility::conversions::to_string_t(\"\")"; - } else if (isFreeFormObject(p)) { + } else if (ModelUtils.isFreeFormObject(openAPI, p)) { return "new Object()"; } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java index cf7a01d188c..7ea25de9cb1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java @@ -747,14 +747,14 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { return prefix + modelName + fullSuffix; } } - if (isAnyTypeSchema(p)) { + if (ModelUtils.isAnyTypeSchema(openAPI, p)) { return prefix + "bool, date, datetime, dict, float, int, list, str, none_type" + suffix; } // Resolve $ref because ModelUtils.isXYZ methods do not automatically resolve references. if (ModelUtils.isNullable(ModelUtils.getReferencedSchema(this.openAPI, p))) { fullSuffix = ", none_type" + suffix; } - if (isFreeFormObject(p) && getAdditionalProperties(p) == null) { + if (ModelUtils.isFreeFormObject(openAPI, p) && getAdditionalProperties(p) == null) { return prefix + "bool, date, datetime, dict, float, int, list, str" + fullSuffix; } if ((ModelUtils.isMapSchema(p) || "object".equals(p.getType())) && getAdditionalProperties(p) != null) { @@ -958,7 +958,7 @@ public class PythonClientCodegen extends PythonLegacyClientCodegen { } String refModelName = getModelName(schema); return toExampleValueRecursive(refModelName, refSchema, objExample, indentationLevel, prefix, exampleLine); - } else if (ModelUtils.isNullType(schema) || isAnyTypeSchema(schema)) { + } else if (ModelUtils.isNullType(schema) || ModelUtils.isAnyTypeSchema(openAPI, schema)) { // The 'null' type is allowed in OAS 3.1 and above. It is not supported by OAS 3.0.x, // though this tooling supports it. return fullPrefix + "None" + closeChars; 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 2ad0470bc15..2930c854919 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 @@ -1593,4 +1593,46 @@ public class ModelUtils { return new SemVer(version); } + + /** + * Return true if the schema value can be any type, i.e. it can be + * the null value, integer, number, string, object or array. + * One use case is when the "type" attribute in the OAS schema is unspecified. + * + * Examples: + * + * arbitraryTypeValue: + * description: This is an arbitrary type schema. + * It is not a free-form object. + * The value can be any type except the 'null' value. + * arbitraryTypeNullableValue: + * description: This is an arbitrary type schema. + * It is not a free-form object. + * The value can be any type, including the 'null' value. + * nullable: true + * + * @param schema the OAS schema. + * @return true if the schema value can be an arbitrary type. + */ + public static boolean isAnyTypeSchema(OpenAPI openAPI, Schema schema) { + if (schema == null) { + once(LOGGER).error("Schema cannot be null in isAnyTypeSchema check"); + return false; + } + + if (isFreeFormObject(openAPI, schema)) { + // make sure it's not free form object + return false; + } + + if (schema.getClass().equals(Schema.class) && schema.get$ref() == null && schema.getType() == null && + (schema.getProperties() == null || schema.getProperties().isEmpty()) && + schema.getAdditionalProperties() == null && schema.getNot() == null && + schema.getEnum() == null) { + return true; + // If and when type arrays are supported in a future OAS specification, + // we could return true if the type array includes all possible JSON schema types. + } + return false; + } }