I'm having some doubts related to the model created using openapi-generator maven plugin. The model is created based on the following yaml schema:
Context: openJDK 17.0.9 + maven 3.8.6
src/main/resources/schema.yaml:
openapi: 3.0.3
info:
title: Test
version: 0.0.0
paths:
/none:
get:
responses:
"200":
description: API not generated yet
components:
schemas:
operation:
type: object
properties:
settings:
$ref: "./settings.yaml#/Settings"
When compiling the project, the target directory contains the following java class (target/generated-sources/openapi/src/main/java/com/test/model/)
package com.test.model;
import java.net.URI;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonTypeName;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.*;
import jakarta.annotation.Generated;
/**
* PGP input operations file structure
*/
@Schema(name = "operation")
@JsonTypeName("operation")
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
public class OperationDTO {
private SettingsDTO settings;
public OperationDTO() {
super();
}
/**
* Constructor with only required parameters
*/
public OperationDTO(SettingsDTO settings) {
this.settings = settings;
}
public OperationDTO settings(SettingsDTO settings) {
this.settings = settings;
return this;
}
/**
* Get settings
* @return settings
*/
@NotNull @Valid
@Schema(name = "settings", requiredMode = Schema.RequiredMode.REQUIRED)
@JsonProperty("settings")
public SettingsDTO getSettings() {
return settings;
}
public void setSettings(SettingsDTO settings) {
this.settings = settings;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OperationDTO operation = (OperationDTO) o;
return Objects.equals(this.settings, operation.settings);
}
@Override
public int hashCode() {
return Objects.hash(settings);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class OperationDTO {\n");
sb.append(" settings: ").append(toIndentedString(settings)).append("\n");
sb.append("}");
return sb.toString();
}
/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}
I expected just constructors/getters/setters to be generated, but there is also this method in the auto-generated model class:
public OperationDTO settings(SettingsDTO settings) {
this.settings = settings;
return this;
}
I don't understand why these "builder"-alike methods are being autogenerated in the class, and I cannot find any configOption in the spring openapi-generator plugin to avoid this, nor documentation explaining why are they created
The issue is that the schema present in the swagger-ui interface is as follows:
{
"operation":{
"tings": "string", //<------ This attribute shouldn't be here!!!!
"settings": {...}
}
}
Also, when trying to validate any wrong JSON object against the schema, the exception informs about the expected parameters as follows:
Unrecognized field \"test\" (class com.test.model.OperationDTO), not marked as ignorable (2 known properties: \"settings\", \"tings\"])
It seems like the tings variable comes from Jackson detecting the settings(...) builder method as a setter, but I would like to avoid this behavior.
I understand I could avoid this by creating the model classes directly in my project, but I'd rather create them using the plugin, since the model spec can change and I find it easier to trace this way.
Can anyone please clarify why those "builder" methods are being created? Is there any way to avoid them?
Thanks a lot!
P.S: My pom.xml file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
</parent>
<groupId>com.test</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<swagger.version>2.2.20</swagger.version>
<springdoc.version>2.3.0</springdoc.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.2.0</version>
<executions>
<execution>
<id>generate-model</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/schemas/schema.yaml</inputSpec>
<generatorName>spring</generatorName>
<modelPackage>com.test.model</modelPackage>
<modelNameSuffix>DTO</modelNameSuffix>
<generateSupportingFiles>false</generateSupportingFiles>
<generateApis>false</generateApis>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<useSpringBoot3>true</useSpringBoot3>
<openApiNullable>true</openApiNullable>
<useSwaggerUI>true</useSwaggerUI>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<useEnumCaseInsensitive>true</useEnumCaseInsensitive>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>