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 eb6522a93189..d290aa5c6abd 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 @@ -41,6 +41,7 @@ public class CodegenParameter { public CodegenProperty mostInnerItems; public Map vendorExtensions = new HashMap(); public boolean hasValidation; + public boolean isNullable; /** * Determines whether this parameter is mandatory. If the parameter is in "path", @@ -150,6 +151,7 @@ public CodegenParameter copy() { output.vendorExtensions = new HashMap(this.vendorExtensions); } output.hasValidation = this.hasValidation; + output.isNullable = this.isNullable; output.isBinary = this.isBinary; output.isByteArray = this.isByteArray; output.isString = this.isString; @@ -269,6 +271,8 @@ public boolean equals(Object o) { return false; if (hasValidation != that.hasValidation) return false; + if (isNullable != that.isNullable) + return false; if (required != that.required) return false; if (maximum != null ? !maximum.equals(that.maximum) : that.maximum != null) @@ -344,6 +348,7 @@ public int hashCode() { result = 31 * result + (mostInnerItems != null ? mostInnerItems.hashCode() : 0); result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0); result = 31 * result + (hasValidation ? 13:31); + result = 31 * result + (isNullable ? 13:31); result = 31 * result + (required ? 13:31); result = 31 * result + (maximum != null ? maximum.hashCode() : 0); result = 31 * result + (exclusiveMaximum ? 13:31); @@ -409,6 +414,7 @@ public java.lang.String toString() { ", mostInnerItems=" + mostInnerItems + ", vendorExtensions=" + vendorExtensions + ", hasValidation=" + hasValidation + + ", isNullable=" + isNullable + ", required=" + required + ", maximum='" + maximum + '\'' + ", exclusiveMaximum=" + exclusiveMaximum + 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 61d1ae831552..01017af3fad7 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 @@ -1789,7 +1789,11 @@ public CodegenProperty fromProperty(String name, Schema p) { if (p.getWriteOnly() != null) { property.isWriteOnly = p.getWriteOnly(); } - if (p.getNullable() != null) { + + // use x-nullable + if (p.getExtensions() != null && p.getExtensions().get("x-nullable") != null) { + property.isNullable = Boolean.valueOf(p.getExtensions().get("x-nullable").toString()); + } else if (p.getNullable() != null) { // use nullable defined in OAS3 property.isNullable = p.getNullable(); } @@ -2649,6 +2653,14 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) LOGGER.warn("warning! Schema not found for parameter \"" + parameter.getName() + "\", using String"); parameterSchema = new StringSchema().description("//TODO automatically added by openapi-generator due to missing type definition."); } + + // x-nullable extension in OAS2 + if (parameter.getExtensions() != null && parameter.getExtensions().get("x-nullable") != null) { + codegenParameter.isNullable = Boolean.valueOf(parameter.getExtensions().get("x-nullable").toString()); + } else if (Boolean.TRUE.equals(parameterSchema.getNullable())) { // use nullable defined in the spec + codegenParameter.isNullable = true; + } + // set default value if (parameterSchema.getDefault() != null) { codegenParameter.defaultValue = toDefaultValue(parameterSchema); @@ -4265,6 +4277,9 @@ public List fromRequestBodyToFormParameters(RequestBody body, // default to csv: codegenParameter.collectionFormat = StringUtils.isEmpty(collectionFormat) ? "csv" : collectionFormat; + // set nullable + setParameterNullable(codegenParameter, codegenProperty); + // recursively add import while (codegenProperty != null) { imports.add(codegenProperty.baseType); @@ -4293,7 +4308,7 @@ public List fromRequestBodyToFormParameters(RequestBody body, public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set imports) { CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); - LOGGER.debug("Debugging fromFormProperty: " + name); + LOGGER.debug("Debugging fromFormProperty {}: {}", name, propertySchema); CodegenProperty codegenProperty = fromProperty(name, propertySchema); codegenParameter.isFormParam = Boolean.TRUE; @@ -4307,7 +4322,6 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set codegenParameter.jsonSchema = Json.pretty(propertySchema); codegenParameter.defaultValue = codegenProperty.getDefaultValue(); - if (codegenProperty.getVendorExtensions() != null && !codegenProperty.getVendorExtensions().isEmpty()) { codegenParameter.vendorExtensions = codegenProperty.getVendorExtensions(); } @@ -4366,6 +4380,8 @@ public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); setParameterExampleValue(codegenParameter); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); //TODO collectionFormat for form parameter not yet supported //codegenParameter.collectionFormat = getCollectionFormat(propertySchema); @@ -4415,6 +4431,9 @@ public CodegenParameter fromRequestBody(RequestBody body, Map sc codegenParameter.isMapContainer = Boolean.TRUE; setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + + // set nullable + setParameterNullable(codegenParameter, codegenProperty); } else if (ModelUtils.isArraySchema(schema)) { final ArraySchema arraySchema = (ArraySchema) schema; Schema inner = arraySchema.getItems(); @@ -4454,6 +4473,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Map sc codegenParameter.isListContainer = Boolean.TRUE; setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); while (codegenProperty != null) { imports.add(codegenProperty.baseType); @@ -4516,6 +4537,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Map sc } } setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); } } else { @@ -4539,6 +4562,8 @@ public CodegenParameter fromRequestBody(RequestBody body, Map sc } setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); } // set the parameter's example value @@ -4636,4 +4661,12 @@ public List fromServerVariables(Map 10. Other values will generated exceptions' + operationId: getOrderById + produces: + - application/xml + - application/json + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + type: integer + maximum: 5 + minimum: 1 + format: int64 + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + operationId: deleteOrder + produces: + - application/xml + - application/json + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + type: string + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Created user object + required: true + schema: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: query + description: The user name for login + required: true + type: string + - name: password + in: query + description: The password for login in clear text + required: true + type: string + responses: + '200': + description: successful operation + schema: + type: string + headers: + X-Rate-Limit: + type: integer + format: int32 + description: calls per hour allowed by the user + X-Expires-After: + type: string + format: date-time + description: date in UTC when toekn expires + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + produces: + - application/xml + - application/json + parameters: [] + responses: + default: + description: successful operation + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: 'The name that needs to be fetched. Use user1 for testing.' + required: true + type: string + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + type: string + - in: body + name: body + description: Updated user object + required: true + schema: + $ref: '#/definitions/User' + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found +securityDefinitions: + petstore_auth: + type: oauth2 + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + flow: implicit + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header +definitions: + Order: + title: Pet Order + description: An order for a pets from the pet store + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Category + User: + title: a User + description: A User who is purchasing from the pet store + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + x-nullable: true + category: + $ref: '#/definitions/Category' + name: + type: string + example: doggie + x-nullable: true + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + x-nullable: true + tags: + x-nullable: true + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/definitions/Tag' + status: + type: string + x-nullable: true + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string diff --git a/modules/openapi-generator/src/test/resources/3_0/petstore_oas3_test.yaml b/modules/openapi-generator/src/test/resources/3_0/petstore_oas3_test.yaml index c9c83e09a6be..370ae3ee32f6 100644 --- a/modules/openapi-generator/src/test/resources/3_0/petstore_oas3_test.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/petstore_oas3_test.yaml @@ -181,6 +181,7 @@ paths: schema: type: integer format: int64 + nullable: true responses: '405': description: Invalid input @@ -200,6 +201,7 @@ paths: status: description: Updated status of the pet type: string + nullable: true delete: tags: - pet