OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.49k stars 6.5k forks source link

[BUG] @Size annotation generated for java.util.UUID field causing issues as @Size does not support UUID. #9256

Open ajinkya-vaze-altus opened 3 years ago

ajinkya-vaze-altus commented 3 years ago

Bug Report Checklist

Description

We are using UUID in one of the path variables for our api. In the open api specification we are putting a minLength constraint on UUID to be minimum 36 characters. We are using openapi-generator-maven-plugin to generate java classes with spring. By default bean validations are on so generator is creating validation annotations for respective fields. The code generator maps UUID to java.util.UUID and adds @Size(min=36) for UUID field. However, as per the documentation of javax.validation.constraints.Size it does not support UUID validation. This is creating a problem for us because we don't want to turn off validations on our beans.

openapi-generator version

We are using openapi-generator-maven plugin.

<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.1.0</version>
OpenAPI declaration file content or url
UUID:
      type: string
      format: uuid
      minLength: 36
Steps to reproduce

Generate code using plugin configuration below:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>5.1.0</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${basedir}/contract/contract.yml</inputSpec>
                <generatorName>spring</generatorName>
                <apiPackage>api</apiPackage>
                <modelPackage>model</modelPackage>
                <modelNameSuffix>Dto</modelNameSuffix>
                <configOptions>
                    <delegatePattern>true</delegatePattern>
                    <interfaceOnly>true</interfaceOnly>
                </configOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
Suggest a fix

I have fixed it by updating the template "beanValidationCore.mustache" to not generate Size annotation with minimum length when type is UUID. I am not sure if this can be used as a permanent fix. If yes, I can raise a PR.

{{^isUuid}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{/isUuid}}
joosterhuis137 commented 6 months ago

This even happens without declaring minLength and/or maxLength. Is this issue being tracked?

We use the following configuration:

Piece of the openapi spec:

    ObjectX:
      required:
        - id
        - uuid
      type: object
      properties:
        id:
          type: integer
          format: int64
        uuid:
          type: string
          format: uuid

Piece of the resulting class:

  @Valid @Size(min = 36, max = 36) 
  @Schema(name = "uuid", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
  @JsonProperty("uuid")
  public UUID getUuid() {
    return uuid;
  }

Using the following configuration:

          <groupId>org.openapitools</groupId>
          <artifactId>openapi-generator-maven-plugin</artifactId>
          <version>7.3.0</version>
         <executions>
        <execution>
              <id>generate-openapi-server</id>
              <goals>
                <goal>generate</goal>
              </goals>
              <configuration>
                <skip>${openapi-generator.skip-dedicated}</skip>
                <generatorName>spring</generatorName>
                <inputSpec>${openapi.generator.input-spec}</inputSpec>
                <output>${project.build.directory}/generated-sources/api-server-java</output>
                <apiPackage>${openapi.generator.server.api-package}</apiPackage>
                <modelPackage>${openapi.generator.server.model-package}</modelPackage>
                <groupId>${project.groupId}</groupId>
                <artifactId>${project.artifactId}-server-java</artifactId>
                <artifactVersion>${project.version}</artifactVersion>
                <modelNameSuffix>DTO</modelNameSuffix>
                <generateApiTests>false</generateApiTests>
                <generateModelTests>false</generateModelTests>
                <configOptions>
                  <library>spring-boot</library>
                  <developerName>redacted</developerName>
                  <developerEmail>redacted</developerEmail>
                  <developerOrganization>redacted</developerOrganization>
                  <developerOrganizationUrl>redacted</developerOrganizationUrl>
                  <artifactUrl>${openapi.generator.gitLabProjectUrl}</artifactUrl>
                  <scmConnection>${openapi.generator.gitHttpsProject}</scmConnection>
                  <scmDeveloperConnection>${openapi.generator.gitSSHProject}</scmDeveloperConnection>
                  <scmUrl>${openapi.generator.gitLabProjectUrl}</scmUrl>
                  <interfaceOnly>true</interfaceOnly>
                  <useSpringBoot3>true</useSpringBoot3>
                  <useJakartaEe>true</useJakartaEe>
                </configOptions>
                <importMappings>
                  <importMapping>Year=java.time.Year</importMapping>
                </importMappings>
              </configuration>
            </execution>