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.75k stars 6.56k forks source link

[BUG] No argument constructor missing #19295

Open poorya-hosseini opened 2 months ago

poorya-hosseini commented 2 months ago

Bug Report Checklist

Description

The generator missing the no argument constructor when x-class-extra-annotation is used. If we add any required properties the no argument constructor is created but when the object does not have any required field the no argument constructor won't be generated.

openapi-generator version

7.7.0

OpenAPI declaration file content or url
    myModelObject:
      x-class-extra-annotation: |
        @lombok.AllArgsConstructor
        @lombok.Builder
      type: object
      properties:
        firstField:
          description: 'it is field one'
          type: number
          format: double
          example: 30000
        secondField:
          description: 'it is field two'
          type: number
          format: double
          example: 30000
Generation Details
<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <version>${openapi.maven.plugin.version}</version>
    <executions>
        <execution>
            <id>generate-client</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>
                    ${project.basedir}/src/main/resources/xxx_api.yml
                </inputSpec>
                <generatorName>spring</generatorName>
                <apiPackage>...</apiPackage>
                <modelPackage>...</modelPackage>
                <configOptions>
                    <useSpringBoot3>true</useSpringBoot3>
                    <reactive>true</reactive>
                    <useResponseEntity>false</useResponseEntity>
                    <useJakartaEe>true</useJakartaEe>
                    <interfaceOnly>true</interfaceOnly>
                    <additionalModelTypeAnnotations>
                        @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
                    </additionalModelTypeAnnotations>
                </configOptions>
                <typeMappings>
                    <typeMapping>Double=java.math.BigDecimal</typeMapping>
                </typeMappings>
                <additionalProperties>removeEnumValuePrefix=false</additionalProperties>
            </configuration>
        </execution>
    </executions>
</plugin>
Generated Class
package com.nordea.nf.calculation.api.contract.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import java.math.BigDecimal;
import java.util.Objects;
import lombok.Generated;

@JsonInclude(Include.NON_NULL)
@JsonTypeName("myModelObject")
public class MyModelObject {
    private BigDecimal firstField;
    private BigDecimal secondField;

    public MyModelObject firstField(BigDecimal firstField) {
        this.firstField = firstField;
        return this;
    }

    @Schema(
        name = "firstField",
        example = "30000",
        description = "it is field one",
        requiredMode = RequiredMode.NOT_REQUIRED
    )
    @JsonProperty("firstField")
    public BigDecimal getFirstField() {
        return this.firstField;
    }

    public void setFirstField(BigDecimal firstField) {
        this.firstField = firstField;
    }

    public MyModelObject secondField(BigDecimal secondField) {
        this.secondField = secondField;
        return this;
    }

    @Schema(
        name = "secondField",
        example = "30000",
        description = "it is field two",
        requiredMode = RequiredMode.NOT_REQUIRED
    )
    @JsonProperty("secondField")
    public BigDecimal getSecondField() {
        return this.secondField;
    }

    public void setSecondField(BigDecimal secondField) {
        this.secondField = secondField;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (o != null && this.getClass() == o.getClass()) {
            MyModelObject myModelObject = (MyModelObject)o;
            return Objects.equals(this.firstField, myModelObject.firstField) && Objects.equals(this.secondField, myModelObject.secondField);
        } else {
            return false;
        }
    }

    public int hashCode() {
        return Objects.hash(new Object[]{this.firstField, this.secondField});
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("class MyModelObject {\n");
        sb.append("    firstField: ").append(this.toIndentedString(this.firstField)).append("\n");
        sb.append("    secondField: ").append(this.toIndentedString(this.secondField)).append("\n");
        sb.append("}");
        return sb.toString();
    }

    private String toIndentedString(Object o) {
        return o == null ? "null" : o.toString().replace("\n", "\n    ");
    }

    @Generated
    public static MyModelObjectBuilder builder() {
        return new MyModelObjectBuilder();
    }

    @Generated
    public MyModelObject(BigDecimal firstField, BigDecimal secondField) {
        this.firstField = firstField;
        this.secondField = secondField;
    }

    @Generated
    public static class MyModelObjectBuilder {
        @Generated
        private BigDecimal firstField;
        @Generated
        private BigDecimal secondField;

        @Generated
        MyModelObjectBuilder() {
        }

        @Generated
        public MyModelObjectBuilder firstField(BigDecimal firstField) {
            this.firstField = firstField;
            return this;
        }

        @Generated
        public MyModelObjectBuilder secondField(BigDecimal secondField) {
            this.secondField = secondField;
            return this;
        }

        @Generated
        public MyModelObject build() {
            return new MyModelObject(this.firstField, this.secondField);
        }

        @Generated
        public String toString() {
            return "MyModelObject.MyModelObjectBuilder(firstField=" + this.firstField + ", secondField=" + this.secondField + ")";
        }
    }
}
Steps to reproduce
Related issues/PRs
Suggest a fix
jpfinne commented 2 months ago

Just specify that you want no argument constructor in all cases. i.e. add @lombok.NoArgsConstructor

poorya-hosseini commented 2 months ago

That has been added as the workaround but I think the code generator should add the no argument constructor as it does when there are required field for the model object.