diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java index 05bd2946bac5..4bcb5dd4bf94 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenModel.java @@ -95,6 +95,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties { public boolean isArray; public boolean hasChildren; public boolean isMap; + public boolean isNull; /** * Indicates the OAS schema specifies "deprecated: true". */ @@ -702,6 +703,16 @@ public class CodegenModel implements IJsonSchemaValidationProperties { this.xmlPrefix = xmlPrefix; } + @Override + public boolean getIsNull() { + return isNull; + } + + @Override + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -730,6 +741,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties { isMap == that.isMap && isDeprecated == that.isDeprecated && hasOnlyReadOnly == that.hasOnlyReadOnly && + isNull == that.isNull && getUniqueItems() == that.getUniqueItems() && getExclusiveMinimum() == that.getExclusiveMinimum() && getExclusiveMaximum() == that.getExclusiveMaximum() && @@ -794,7 +806,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties { getDescription(), getClassVarName(), getModelJson(), getDataType(), getXmlPrefix(), getXmlNamespace(), getXmlName(), getClassFilename(), getUnescapedDescription(), getDiscriminator(), getDefaultValue(), getArrayModelType(), isAlias, isString, isInteger, isLong, isNumber, isNumeric, isFloat, isDouble, - isDate, isDateTime, + isDate, isDateTime, isNull, getVars(), getAllVars(), getRequiredVars(), getOptionalVars(), getReadOnlyVars(), getReadWriteVars(), getParentVars(), getAllowableValues(), getMandatory(), getAllMandatory(), getImports(), hasVars, isEmptyVars(), hasMoreModels, hasEnums, isEnum, isNullable, hasRequired, hasOptional, isArray, @@ -885,6 +897,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties { sb.append(", items='").append(items).append('\''); sb.append(", additionalProperties='").append(additionalProperties).append('\''); sb.append(", isModel='").append(isModel).append('\''); + sb.append(", isNull='").append(isNull); sb.append('}'); return sb.toString(); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java index 39cca3eeb7a5..7c6f80ae8430 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java @@ -101,6 +101,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { public Number multipleOf; private Integer maxProperties; private Integer minProperties; + public boolean isNull; public CodegenParameter copy() { CodegenParameter output = new CodegenParameter(); @@ -147,6 +148,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { output.minimum = this.minimum; output.pattern = this.pattern; output.additionalProperties = this.additionalProperties; + output.isNull = this.isNull; if (this._enum != null) { output._enum = new ArrayList(this._enum); @@ -200,7 +202,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { @Override public int hashCode() { - return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isAnyType, isArray, isMap, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf); + return Objects.hash(isFormParam, isQueryParam, isPathParam, isHeaderParam, isCookieParam, isBodyParam, isContainer, isCollectionFormatMulti, isPrimitiveType, isModel, isExplode, baseName, paramName, dataType, datatypeWithEnum, dataFormat, collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, style, example, jsonSchema, isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBinary, isBoolean, isDate, isDateTime, isUuid, isUri, isEmail, isFreeFormObject, isAnyType, isArray, isMap, isFile, isEnum, _enum, allowableValues, items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation, getMaxProperties(), getMinProperties(), isNullable, required, getMaximum(), getExclusiveMaximum(), getMinimum(), getExclusiveMinimum(), getMaxLength(), getMinLength(), getPattern(), getMaxItems(), getMinItems(), getUniqueItems(), contentType, multipleOf, isNull); } @Override @@ -244,6 +246,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { hasValidation == that.hasValidation && isNullable == that.isNullable && required == that.required && + isNull == that.isNull && getExclusiveMaximum() == that.getExclusiveMaximum() && getExclusiveMinimum() == that.getExclusiveMinimum() && getUniqueItems() == that.getUniqueItems() && @@ -357,6 +360,7 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { sb.append(", uniqueItems=").append(uniqueItems); sb.append(", contentType=").append(contentType); sb.append(", multipleOf=").append(multipleOf); + sb.append(", isNull=").append(isNull); sb.append('}'); return sb.toString(); } @@ -568,5 +572,15 @@ public class CodegenParameter implements IJsonSchemaValidationProperties { public void setRequiredVars(List requiredVars) { this.requiredVars = requiredVars; } + + @Override + public boolean getIsNull() { + return isNull; + } + + @Override + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java index c3cbfe569250..b956a3ea7e19 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenProperty.java @@ -132,6 +132,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti public boolean isUuid; public boolean isUri; public boolean isEmail; + public boolean isNull; /** * The type is a free-form object, i.e. it is a map of string to values with no declared properties. * A OAS free-form schema may include the 'additionalProperties' attribute, which puts a constraint @@ -676,6 +677,16 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti this.requiredVars = requiredVars; } + @Override + public boolean getIsNull() { + return isNull; + } + + @Override + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("CodegenProperty{"); @@ -764,6 +775,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti sb.append(", xmlName='").append(xmlName).append('\''); sb.append(", xmlNamespace='").append(xmlNamespace).append('\''); sb.append(", isXmlWrapped=").append(isXmlWrapped); + sb.append(", isNull=").append(isNull); sb.append('}'); return sb.toString(); } @@ -812,6 +824,7 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti isInherited == that.isInherited && isXmlAttribute == that.isXmlAttribute && isXmlWrapped == that.isXmlWrapped && + isNull == that.isNull && Objects.equals(openApiType, that.openApiType) && Objects.equals(baseName, that.baseName) && Objects.equals(complexType, that.complexType) && @@ -873,6 +886,6 @@ public class CodegenProperty implements Cloneable, IJsonSchemaValidationProperti items, mostInnerItems, additionalProperties, vars, requiredVars, vendorExtensions, hasValidation, isInherited, discriminatorValue, nameInCamelCase, nameInSnakeCase, enumName, maxItems, minItems, isXmlAttribute, xmlPrefix, xmlName, - xmlNamespace, isXmlWrapped); + xmlNamespace, isXmlWrapped, isNull); } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java index b3ceedb149aa..7762676b7ca8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java @@ -57,6 +57,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties { public boolean isArray; public boolean isBinary = false; public boolean isFile = false; + public boolean isNull; public Object schema; public String jsonSchema; public Map vendorExtensions = new HashMap(); @@ -84,7 +85,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties { isString, isNumeric, isInteger, isLong, isNumber, isFloat, isDouble, isDecimal, isByteArray, isBoolean, isDate, isDateTime, isUuid, isEmail, isModel, isFreeFormObject, isAnyType, isDefault, simpleType, primitiveType, isMap, isArray, isBinary, isFile, schema, jsonSchema, vendorExtensions, items, additionalProperties, - vars, requiredVars, + vars, requiredVars, isNull, getMaxProperties(), getMinProperties(), uniqueItems, getMaxItems(), getMinItems(), getMaxLength(), getMinLength(), exclusiveMinimum, exclusiveMaximum, getMinimum(), getMaximum(), getPattern(), is1xx, is2xx, is3xx, is4xx, is5xx); @@ -122,6 +123,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties { isFile == that.isFile && items == that.items && additionalProperties == that.additionalProperties && + isNull == that.isNull && is1xx == that.is1xx && is2xx == that.is2xx && is3xx == that.is3xx && @@ -423,6 +425,7 @@ public class CodegenResponse implements IJsonSchemaValidationProperties { sb.append(", additionalProperties='").append(additionalProperties).append('\''); sb.append(", vars='").append(vars).append('\''); sb.append(", requiredVars='").append(requiredVars).append('\''); + sb.append(", isNull='").append(isNull); sb.append('}'); return sb.toString(); } @@ -443,4 +446,14 @@ public class CodegenResponse implements IJsonSchemaValidationProperties { return true; return false; } + + @Override + public boolean getIsNull() { + return isNull; + } + + @Override + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } } 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 9738f9a94529..9f063bef496b 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 @@ -2306,6 +2306,8 @@ public class DefaultCodegen implements CodegenConfig { m.arrayModelType = arrayProperty.complexType; addParentContainer(m, name, schema); ModelUtils.syncValidationProperties(schema, m); + } else if (ModelUtils.isNullType(schema)) { + m.isNull = true; } else if (schema instanceof ComposedSchema) { final ComposedSchema composed = (ComposedSchema) schema; Map properties = new LinkedHashMap(); @@ -3279,6 +3281,8 @@ public class DefaultCodegen implements CodegenConfig { innerSchema = new StringSchema().description("//TODO automatically added by openapi-generator due to undefined type"); p.setAdditionalProperties(innerSchema); } + } else if (ModelUtils.isNullType(p)) { + property.isNull = true; } //Inline enum case: @@ -4044,6 +4048,7 @@ public class DefaultCodegen implements CodegenConfig { if (r.schema != null) { Map allSchemas = null; CodegenProperty cp = fromProperty("response", responseSchema); + r.isNull = cp.isNull; if (ModelUtils.isArraySchema(responseSchema)) { ArraySchema as = (ArraySchema) responseSchema; @@ -4317,6 +4322,8 @@ public class DefaultCodegen implements CodegenConfig { imports.add(codegenProperty.baseType); codegenProperty = codegenProperty.items; } + } else if (ModelUtils.isNullType(parameterSchema)) { + codegenParameter.isNull = true; } /* TODO revise the logic below } else { @@ -6146,6 +6153,7 @@ public class DefaultCodegen implements CodegenConfig { } else { codegenParameter.baseName = bodyParameterName; } + codegenParameter.isNull = codegenProperty.isNull; codegenParameter.isPrimitiveType = true; codegenParameter.baseType = codegenProperty.baseType; codegenParameter.dataType = codegenProperty.dataType; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java index 7a1a0323a083..9b0ad0f89f95 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/IJsonSchemaValidationProperties.java @@ -90,4 +90,8 @@ public interface IJsonSchemaValidationProperties { List getRequiredVars(); void setRequiredVars(List requiredVars); + + boolean getIsNull(); + + void setIsNull(boolean isNull); } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java index 9233174859a1..87959fbb2ed5 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java @@ -2557,6 +2557,23 @@ public class DefaultCodegenTest { assertEquals(cm.isString, false); assertEquals(cm.isDate, true); + modelName = "NullModel"; + sc = openAPI.getComponents().getSchemas().get(modelName); + cm = codegen.fromModel(modelName, sc); + assertEquals(cm.isNull, true); + + modelName = "ObjectWithTypeNullProperties"; + sc = openAPI.getComponents().getSchemas().get(modelName); + cm = codegen.fromModel(modelName, sc); + assertEquals(cm.getVars().get(0).isNull, true); + assertEquals(cm.getVars().get(1).getItems().isNull, true); + assertEquals(cm.getAdditionalProperties().isNull, true); + + modelName = "ArrayOfNulls"; + sc = openAPI.getComponents().getSchemas().get(modelName); + cm = codegen.fromModel(modelName, sc); + assertEquals(cm.getItems().isNull, true); + modelName = "ObjectWithDateWithValidation"; sc = openAPI.getComponents().getSchemas().get(modelName); cm = codegen.fromModel(modelName, sc); @@ -2618,6 +2635,20 @@ public class DefaultCodegenTest { assertEquals(co.bodyParams.get(0).isDateTime, true); assertEquals(co.responses.get(0).isString, false); assertEquals(co.responses.get(0).isDateTime, true); + + path = "/null/{param}"; + operation = openAPI.getPaths().get(path).getPost(); + co = codegen.fromOperation(path, "POST", operation, null); + assertEquals(co.pathParams.get(0).isNull, true); + assertEquals(co.bodyParams.get(0).isNull, true); + assertEquals(co.responses.get(0).isNull, true); + + path = "/ref_null/{param}"; + operation = openAPI.getPaths().get(path).getPost(); + co = codegen.fromOperation(path, "POST", operation, null); + assertEquals(co.pathParams.get(0).isNull, true); + assertEquals(co.bodyParams.get(0).isNull, true); + assertEquals(co.responses.get(0).isNull, true); } @Test diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_7651.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_7651.yaml index ce2bfff7fac7..f35d64b4b358 100644 --- a/modules/openapi-generator/src/test/resources/3_0/issue_7651.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/issue_7651.yaml @@ -120,8 +120,73 @@ paths: type: string format: date-time pattern: '^2020.*' + /null/{param}: + post: + tags: + - isX + operationId: null + parameters: + - name: param + in: path + required: true + schema: + type: 'null' + requestBody: + content: + application/json: + schema: + type: 'null' + required: true + responses: + 200: + description: success + content: + application/json: + schema: + type: 'null' + /ref_null/{param}: + post: + tags: + - isX + operationId: null + parameters: + - name: param + in: path + required: true + schema: + $ref: '#/components/schemas/NullModel' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NullModel' + required: true + responses: + 200: + description: success + content: + application/json: + schema: + $ref: '#/components/schemas/NullModel' components: schemas: + NullModel: + type: 'null' + ObjectWithTypeNullProperties: + type: object + properties: + nullProp: + type: 'null' + listOfNulls: + type: array + items: + type: 'null' + additionalProperties: + type: 'null' + ArrayOfNulls: + type: array + items: + type: 'null' DateWithValidation: type: string format: date