From bc4fd031535180e3d19b9bde7b3bc98b56e329f6 Mon Sep 17 00:00:00 2001 From: Richard Alm Date: Sun, 8 Dec 2024 23:29:26 +0100 Subject: [PATCH 1/6] Exposed the serializable-model when generating client models. --- .../generator/deployment/CodegenConfig.java | 15 ++- .../codegen/OpenApiGeneratorCodeGenBase.java | 54 +++----- .../OpenApiClientGeneratorWrapper.java | 33 +++-- client/integration-tests/pom.xml | 1 + .../serializable-model/pom.xml | 94 +++++++++++++ .../quarkus-non-serializable-openapi.yaml | 125 ++++++++++++++++++ .../openapi/quarkus-serializable-openapi.yaml | 125 ++++++++++++++++++ .../src/main/resources/application.properties | 4 + ...sSerializableModelRestEasyClassicTest.java | 28 ++++ ...SerializableModelRestEasyReactiveTest.java | 28 ++++ docs/modules/ROOT/pages/client.adoc | 11 ++ 11 files changed, 459 insertions(+), 59 deletions(-) create mode 100644 client/integration-tests/serializable-model/pom.xml create mode 100644 client/integration-tests/serializable-model/src/main/openapi/quarkus-non-serializable-openapi.yaml create mode 100644 client/integration-tests/serializable-model/src/main/openapi/quarkus-serializable-openapi.yaml create mode 100644 client/integration-tests/serializable-model/src/main/resources/application.properties create mode 100644 client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java create mode 100644 client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java index f163f25ee..c09655d6d 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java @@ -1,17 +1,17 @@ package io.quarkiverse.openapi.generator.deployment; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import io.quarkiverse.openapi.generator.deployment.codegen.OpenApiGeneratorOutputPaths; import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; import io.smallrye.config.common.utils.StringUtil; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + // This configuration is read in codegen phase (before build time), the annotation is for document purposes and avoiding quarkus warns @ConfigRoot(name = CodegenConfig.CODEGEN_TIME_CONFIG_PREFIX, phase = ConfigPhase.BUILD_TIME) public class CodegenConfig extends GlobalCodegenConfig { @@ -73,7 +73,8 @@ public enum ConfigName { REMOVE_OPERATION_ID_PREFIX_COUNT("remove-operation-id-prefix-count"), GENERATE_APIS("generate-apis"), GENERATE_MODELS("generate-models"), - BEAN_VALIDATION("use-bean-validation"); + BEAN_VALIDATION("use-bean-validation"), + SERIALIZABLE_MODEL("serializable-model"); private final String name; diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java index 0431e6777..6813e8e30 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java @@ -1,39 +1,5 @@ package io.quarkiverse.openapi.generator.deployment.codegen; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ADDITIONAL_ENUM_TYPE_UNEXPECTED_MEMBER_NAME_DEFAULT; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ADDITIONAL_ENUM_TYPE_UNEXPECTED_MEMBER_STRING_VALUE_DEFAULT; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getGlobalConfigName; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSanitizedFileName; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSpecConfigName; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.API_NAME_SUFFIX; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.BASE_PACKAGE; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.DEFAULT_SECURITY_SCHEME; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.EXCLUDE; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.INCLUDE; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.INPUT_BASE_DIR; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.MODEL_NAME_PREFIX; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.MODEL_NAME_SUFFIX; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX_COUNT; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX_DELIMITER; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.TEMPLATE_BASE_DIR; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.VALIDATE_SPEC; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.eclipse.microprofile.config.Config; -import org.openapitools.codegen.config.GlobalSettings; - import io.quarkiverse.openapi.generator.deployment.CodegenConfig; import io.quarkiverse.openapi.generator.deployment.OpenApiGeneratorOptions; import io.quarkiverse.openapi.generator.deployment.circuitbreaker.CircuitBreakerConfigurationParser; @@ -46,6 +12,23 @@ import io.quarkus.deployment.CodeGenContext; import io.quarkus.deployment.CodeGenProvider; import io.smallrye.config.SmallRyeConfig; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.eclipse.microprofile.config.Config; +import org.openapitools.codegen.config.GlobalSettings; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.*; /** * Code generation for OpenApi Client. Generates Java classes from OpenApi spec files located in src/main/openapi or @@ -317,6 +300,9 @@ protected void generate(OpenApiGeneratorOptions options) { getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.SCHEMA_MAPPINGS, String.class, String.class) .ifPresent(generator::withSchemaMappings); + getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.SERIALIZABLE_MODEL, String.class) + .ifPresent(generator::withSerialiableModel); + getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.NORMALIZER, String.class, String.class) .ifPresent(generator::withOpenApiNormalizer); diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java index 7d34db5e4..73b99f572 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java @@ -1,28 +1,21 @@ package io.quarkiverse.openapi.generator.deployment.wrapper; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSanitizedFileName; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.resolveApiPackage; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.resolveModelPackage; +import io.smallrye.config.common.utils.StringUtil; +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.config.GlobalSettings; + +import java.io.File; +import java.nio.file.Path; +import java.util.*; + +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; import static io.quarkiverse.openapi.generator.deployment.wrapper.QuarkusJavaClientCodegen.QUARKUS_GENERATOR_NAME; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static java.util.Objects.requireNonNull; import static org.openapitools.codegen.languages.AbstractJavaCodegen.ADDITIONAL_MODEL_TYPE_ANNOTATIONS; -import java.io.File; -import java.nio.file.Path; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.openapitools.codegen.CodegenConstants; -import org.openapitools.codegen.DefaultGenerator; -import org.openapitools.codegen.config.GlobalSettings; - -import io.smallrye.config.common.utils.StringUtil; - /** * Wrapper for the OpenAPIGen tool. * This is the same as calling the Maven plugin or the CLI. @@ -111,7 +104,6 @@ private void setDefaults() { this.configurator.addAdditionalProperty("use-bean-validation", FALSE); this.configurator.addAdditionalProperty("use-field-name-in-part-filename", FALSE); this.configurator.addAdditionalProperty("verbose", FALSE); - // TODO: expose as properties https://github.com/quarkiverse/quarkus-openapi-generator/issues/869 this.configurator.addAdditionalProperty(CodegenConstants.SERIALIZABLE_MODEL, FALSE); } @@ -198,6 +190,11 @@ public OpenApiClientGeneratorWrapper withOpenApiNormalizer(final Mapconfig-key github without-oidc + serializable-model diff --git a/client/integration-tests/serializable-model/pom.xml b/client/integration-tests/serializable-model/pom.xml new file mode 100644 index 000000000..80df64ac6 --- /dev/null +++ b/client/integration-tests/serializable-model/pom.xml @@ -0,0 +1,94 @@ + + + + quarkus-openapi-generator-integration-tests + io.quarkiverse.openapi.generator + 3.0.0-SNAPSHOT + + 4.0.0 + + quarkus-openapi-generator-it-serializable-model + Quarkus - Openapi Generator - Integration Tests - Client - Serializable model + Example project for general usage + + + + io.quarkiverse.openapi.generator + quarkus-openapi-generator + + + org.assertj + assertj-core + test + + + io.quarkus + quarkus-junit5 + test + + + + + + io.quarkus + quarkus-maven-plugin + true + + + + build + generate-code + generate-code-tests + + + + + + + + + native-image + + + native + + + + + + maven-surefire-plugin + + ${native.surefire.skip} + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + + ${project.build.directory}/${project.build.finalName}-runner + + org.jboss.logmanager.LogManager + + ${maven.home} + + + + + + + + + native + + + + + \ No newline at end of file diff --git a/client/integration-tests/serializable-model/src/main/openapi/quarkus-non-serializable-openapi.yaml b/client/integration-tests/serializable-model/src/main/openapi/quarkus-non-serializable-openapi.yaml new file mode 100644 index 000000000..ec431be5e --- /dev/null +++ b/client/integration-tests/serializable-model/src/main/openapi/quarkus-non-serializable-openapi.yaml @@ -0,0 +1,125 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Animals - OpenAPI 3.0", + "version": "1.0.5" + }, + "servers": [ + { + "url": "/api/v3" + } + ], + "tags": [ + { + "name": "primate", + "description": "Everything about Primates" + } + ], + "paths": { + "/primate/{id}": { + "get": { + "tags": [ + "primate" + ], + "summary": "Find primate by ID", + "description": "Returns a single primate", + "operationId": "getPrimateById", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of primate to return", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Primate" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Primate not found" + } + } + } + } + }, + "components": { + "schemas": { + "Animal": { + "type": "object", + "properties": { + "born": { + "type": "string", + "description": "Dated Base extension.", + "format": "date-time" + }, + "deceased": { + "type": "string", + "description": "Dated Base extension.", + "format": "date-time" + } + }, + "xml": { + "name": "animal" + } + }, + "Mammal": { + "type": "object", + "allOf": [ { + "$ref": "#/components/schemas/Animal" + } ], + "properties": { + "gender": { + "type": "string", + "enum": [ + "female", + "male" + ] + } + }, + "xml": { + "name": "mammal" + } + }, + "Primate": { + "required": [ + "name" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Mammal" + } + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "name": { + "type": "string", + "example": "jane doe" + } + }, + "xml": { + "name": "primate" + } + } + } + } +} diff --git a/client/integration-tests/serializable-model/src/main/openapi/quarkus-serializable-openapi.yaml b/client/integration-tests/serializable-model/src/main/openapi/quarkus-serializable-openapi.yaml new file mode 100644 index 000000000..ec431be5e --- /dev/null +++ b/client/integration-tests/serializable-model/src/main/openapi/quarkus-serializable-openapi.yaml @@ -0,0 +1,125 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Animals - OpenAPI 3.0", + "version": "1.0.5" + }, + "servers": [ + { + "url": "/api/v3" + } + ], + "tags": [ + { + "name": "primate", + "description": "Everything about Primates" + } + ], + "paths": { + "/primate/{id}": { + "get": { + "tags": [ + "primate" + ], + "summary": "Find primate by ID", + "description": "Returns a single primate", + "operationId": "getPrimateById", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of primate to return", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Primate" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Primate not found" + } + } + } + } + }, + "components": { + "schemas": { + "Animal": { + "type": "object", + "properties": { + "born": { + "type": "string", + "description": "Dated Base extension.", + "format": "date-time" + }, + "deceased": { + "type": "string", + "description": "Dated Base extension.", + "format": "date-time" + } + }, + "xml": { + "name": "animal" + } + }, + "Mammal": { + "type": "object", + "allOf": [ { + "$ref": "#/components/schemas/Animal" + } ], + "properties": { + "gender": { + "type": "string", + "enum": [ + "female", + "male" + ] + } + }, + "xml": { + "name": "mammal" + } + }, + "Primate": { + "required": [ + "name" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Mammal" + } + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "name": { + "type": "string", + "example": "jane doe" + } + }, + "xml": { + "name": "primate" + } + } + } + } +} diff --git a/client/integration-tests/serializable-model/src/main/resources/application.properties b/client/integration-tests/serializable-model/src/main/resources/application.properties new file mode 100644 index 000000000..cb3aaf694 --- /dev/null +++ b/client/integration-tests/serializable-model/src/main/resources/application.properties @@ -0,0 +1,4 @@ +quarkus.openapi-generator.codegen.spec.quarkus_serializable_openapi_yaml.serializable-model=true +quarkus.openapi-generator.codegen.spec.quarkus_serializable_openapi_yaml.base-package=io.quarkiverse.serializable +quarkus.openapi-generator.codegen.spec.quarkus_non_serializable_openapi_yaml.base-package=io.quarkiverse.non.serializable +quarkus.keycloak.devservices.enabled=false \ No newline at end of file diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java new file mode 100644 index 000000000..73990a359 --- /dev/null +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java @@ -0,0 +1,28 @@ +package io.quarkiverse.openapi.generator.it; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.io.Serializable; + +import static org.assertj.core.api.Assertions.assertThat; + +@QuarkusTest +@Tag("resteasy-classic") +class QuarkusSerializableModelRestEasyClassicTest { + + @Test + void verifySerializableIsEnabled() { + var interfaces = io.quarkiverse.serializable.model.Animal.class.getInterfaces(); + + assertThat(interfaces).contains(Serializable.class); + } + + @Test + void verifySerializableIsNotEnabled() { + var interfaces = io.quarkiverse.non.serializable.model.Animal.class.getInterfaces(); + + assertThat(interfaces).doesNotContain(Serializable.class); + } +} diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java new file mode 100644 index 000000000..56492a2de --- /dev/null +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java @@ -0,0 +1,28 @@ +package io.quarkiverse.openapi.generator.it; + +import io.quarkus.test.junit.QuarkusTest; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.io.Serializable; + +import static org.assertj.core.api.Assertions.assertThat; + +@QuarkusTest +@Tag("resteasy-reactive") +class QuarkusSerializableModelRestEasyReactiveTest { + + @Test + void verifySerializableIsEnabled() { + var interfaces = io.quarkiverse.serializable.model.Animal.class.getInterfaces(); + + assertThat(interfaces).contains(Serializable.class); + } + + @Test + void verifySerializableIsNotEnabled() { + var interfaces = io.quarkiverse.non.serializable.model.Animal.class.getInterfaces(); + + assertThat(interfaces).doesNotContain(Serializable.class); + } +} diff --git a/docs/modules/ROOT/pages/client.adoc b/docs/modules/ROOT/pages/client.adoc index fa51d0525..7ea4386b0 100644 --- a/docs/modules/ROOT/pages/client.adoc +++ b/docs/modules/ROOT/pages/client.adoc @@ -183,6 +183,17 @@ include::./includes/generate-apis.adoc[leveloffset=+1, opts=optional] include::./includes/generate-models.adoc[leveloffset=+1, opts=optional] +[[generate-serilazble-models]] +== Generate Serilazable Models + +If you need to have the generated models to implement `java.io.Serializable`-interface then set the `serializable-model` +to true: + +[source,properties] +---- +quarkus.openapi-generator.codegen.spec.my_openapi_yaml.serializable-model=true +---- + == Known Limitations === Supported Arguments From ea2adef6d7e331af0761a04f366f7f06219bb9d9 Mon Sep 17 00:00:00 2001 From: Richard Alm Date: Mon, 9 Dec 2024 00:04:09 +0100 Subject: [PATCH 2/6] Optimnized imports and fixed formatting --- .../generator/deployment/CodegenConfig.java | 12 +++---- .../codegen/OpenApiGeneratorCodeGenBase.java | 35 ++++++++++--------- .../OpenApiClientGeneratorWrapper.java | 19 +++++----- ...sSerializableModelRestEasyClassicTest.java | 9 ++--- ...SerializableModelRestEasyReactiveTest.java | 9 ++--- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java index c09655d6d..aa707bc7e 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/CodegenConfig.java @@ -1,17 +1,17 @@ package io.quarkiverse.openapi.generator.deployment; -import io.quarkiverse.openapi.generator.deployment.codegen.OpenApiGeneratorOutputPaths; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConfigPhase; -import io.quarkus.runtime.annotations.ConfigRoot; -import io.smallrye.config.common.utils.StringUtil; - import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import io.quarkiverse.openapi.generator.deployment.codegen.OpenApiGeneratorOutputPaths; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.common.utils.StringUtil; + // This configuration is read in codegen phase (before build time), the annotation is for document purposes and avoiding quarkus warns @ConfigRoot(name = CodegenConfig.CODEGEN_TIME_CONFIG_PREFIX, phase = ConfigPhase.BUILD_TIME) public class CodegenConfig extends GlobalCodegenConfig { diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java index 6813e8e30..4c9af1007 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java @@ -1,20 +1,7 @@ package io.quarkiverse.openapi.generator.deployment.codegen; -import io.quarkiverse.openapi.generator.deployment.CodegenConfig; -import io.quarkiverse.openapi.generator.deployment.OpenApiGeneratorOptions; -import io.quarkiverse.openapi.generator.deployment.circuitbreaker.CircuitBreakerConfigurationParser; -import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiClassicClientGeneratorWrapper; -import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiClientGeneratorWrapper; -import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiReactiveClientGeneratorWrapper; -import io.quarkus.bootstrap.prebuild.CodeGenException; -import io.quarkus.builder.Version; -import io.quarkus.deployment.Capability; -import io.quarkus.deployment.CodeGenContext; -import io.quarkus.deployment.CodeGenProvider; -import io.smallrye.config.SmallRyeConfig; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.eclipse.microprofile.config.Config; -import org.openapitools.codegen.config.GlobalSettings; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.*; import java.io.IOException; import java.nio.file.Files; @@ -27,8 +14,22 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.*; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.eclipse.microprofile.config.Config; +import org.openapitools.codegen.config.GlobalSettings; + +import io.quarkiverse.openapi.generator.deployment.CodegenConfig; +import io.quarkiverse.openapi.generator.deployment.OpenApiGeneratorOptions; +import io.quarkiverse.openapi.generator.deployment.circuitbreaker.CircuitBreakerConfigurationParser; +import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiClassicClientGeneratorWrapper; +import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiClientGeneratorWrapper; +import io.quarkiverse.openapi.generator.deployment.wrapper.OpenApiReactiveClientGeneratorWrapper; +import io.quarkus.bootstrap.prebuild.CodeGenException; +import io.quarkus.builder.Version; +import io.quarkus.deployment.Capability; +import io.quarkus.deployment.CodeGenContext; +import io.quarkus.deployment.CodeGenProvider; +import io.smallrye.config.SmallRyeConfig; /** * Code generation for OpenApi Client. Generates Java classes from OpenApi spec files located in src/main/openapi or diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java index 73b99f572..d372615ca 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java @@ -1,14 +1,5 @@ package io.quarkiverse.openapi.generator.deployment.wrapper; -import io.smallrye.config.common.utils.StringUtil; -import org.openapitools.codegen.CodegenConstants; -import org.openapitools.codegen.DefaultGenerator; -import org.openapitools.codegen.config.GlobalSettings; - -import java.io.File; -import java.nio.file.Path; -import java.util.*; - import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; import static io.quarkiverse.openapi.generator.deployment.wrapper.QuarkusJavaClientCodegen.QUARKUS_GENERATOR_NAME; import static java.lang.Boolean.FALSE; @@ -16,6 +7,16 @@ import static java.util.Objects.requireNonNull; import static org.openapitools.codegen.languages.AbstractJavaCodegen.ADDITIONAL_MODEL_TYPE_ANNOTATIONS; +import java.io.File; +import java.nio.file.Path; +import java.util.*; + +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.config.GlobalSettings; + +import io.smallrye.config.common.utils.StringUtil; + /** * Wrapper for the OpenAPIGen tool. * This is the same as calling the Maven plugin or the CLI. diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java index 73990a359..8ac6d3d85 100644 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java @@ -1,12 +1,13 @@ package io.quarkiverse.openapi.generator.it; -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.io.Serializable; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; @QuarkusTest @Tag("resteasy-classic") diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java index 56492a2de..8119de88a 100644 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java @@ -1,12 +1,13 @@ package io.quarkiverse.openapi.generator.it; -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.io.Serializable; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; @QuarkusTest @Tag("resteasy-reactive") From 337206403f1f8b6c9d2e596a22073e54b4f8de25 Mon Sep 17 00:00:00 2001 From: Richard Alm Date: Mon, 9 Dec 2024 00:21:44 +0100 Subject: [PATCH 3/6] Refactoring, changed from String to Boolean when reading the config. --- .../deployment/codegen/OpenApiGeneratorCodeGenBase.java | 2 +- .../deployment/wrapper/OpenApiClientGeneratorWrapper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java index 4c9af1007..5b8cb58e0 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java @@ -301,7 +301,7 @@ protected void generate(OpenApiGeneratorOptions options) { getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.SCHEMA_MAPPINGS, String.class, String.class) .ifPresent(generator::withSchemaMappings); - getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.SERIALIZABLE_MODEL, String.class) + getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.SERIALIZABLE_MODEL, Boolean.class) .ifPresent(generator::withSerialiableModel); getValues(smallRyeConfig, openApiFilePath, CodegenConfig.ConfigName.NORMALIZER, String.class, String.class) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java index d372615ca..0e5cbbcbd 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java @@ -191,7 +191,7 @@ public OpenApiClientGeneratorWrapper withOpenApiNormalizer(final Map Date: Tue, 10 Dec 2024 16:57:19 +0100 Subject: [PATCH 4/6] Refactoring based on feedback on PR --- .../codegen/OpenApiGeneratorCodeGenBase.java | 20 +++++++++++++++++-- .../src/main/resources/application.properties | 6 ++++-- ...sSerializableModelRestEasyClassicTest.java | 4 ++-- ...SerializableModelRestEasyReactiveTest.java | 4 ++-- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java index 5b8cb58e0..c4f69013b 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/codegen/OpenApiGeneratorCodeGenBase.java @@ -1,7 +1,23 @@ package io.quarkiverse.openapi.generator.deployment.codegen; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.*; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ADDITIONAL_ENUM_TYPE_UNEXPECTED_MEMBER_NAME_DEFAULT; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ADDITIONAL_ENUM_TYPE_UNEXPECTED_MEMBER_STRING_VALUE_DEFAULT; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getGlobalConfigName; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSanitizedFileName; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSpecConfigName; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.API_NAME_SUFFIX; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.BASE_PACKAGE; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.DEFAULT_SECURITY_SCHEME; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.EXCLUDE; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.INCLUDE; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.INPUT_BASE_DIR; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.MODEL_NAME_PREFIX; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.MODEL_NAME_SUFFIX; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX_COUNT; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.REMOVE_OPERATION_ID_PREFIX_DELIMITER; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.TEMPLATE_BASE_DIR; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.ConfigName.VALIDATE_SPEC; import java.io.IOException; import java.nio.file.Files; diff --git a/client/integration-tests/serializable-model/src/main/resources/application.properties b/client/integration-tests/serializable-model/src/main/resources/application.properties index cb3aaf694..30fc60530 100644 --- a/client/integration-tests/serializable-model/src/main/resources/application.properties +++ b/client/integration-tests/serializable-model/src/main/resources/application.properties @@ -1,4 +1,6 @@ quarkus.openapi-generator.codegen.spec.quarkus_serializable_openapi_yaml.serializable-model=true -quarkus.openapi-generator.codegen.spec.quarkus_serializable_openapi_yaml.base-package=io.quarkiverse.serializable -quarkus.openapi-generator.codegen.spec.quarkus_non_serializable_openapi_yaml.base-package=io.quarkiverse.non.serializable +quarkus.openapi-generator.codegen.spec.quarkus_serializable_openapi_yaml.base-package=org.acme.serializable + +quarkus.openapi-generator.codegen.spec.quarkus_non_serializable_openapi_yaml.base-package=org.acme.non.serializable + quarkus.keycloak.devservices.enabled=false \ No newline at end of file diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java index 8ac6d3d85..4f2e20f33 100644 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java @@ -15,14 +15,14 @@ class QuarkusSerializableModelRestEasyClassicTest { @Test void verifySerializableIsEnabled() { - var interfaces = io.quarkiverse.serializable.model.Animal.class.getInterfaces(); + var interfaces = org.acme.serializable.model.Animal.class.getInterfaces(); assertThat(interfaces).contains(Serializable.class); } @Test void verifySerializableIsNotEnabled() { - var interfaces = io.quarkiverse.non.serializable.model.Animal.class.getInterfaces(); + var interfaces = org.acme.non.serializable.model.Animal.class.getInterfaces(); assertThat(interfaces).doesNotContain(Serializable.class); } diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java index 8119de88a..24d0ff6e9 100644 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java @@ -15,14 +15,14 @@ class QuarkusSerializableModelRestEasyReactiveTest { @Test void verifySerializableIsEnabled() { - var interfaces = io.quarkiverse.serializable.model.Animal.class.getInterfaces(); + var interfaces = org.acme.serializable.model.Animal.class.getInterfaces(); assertThat(interfaces).contains(Serializable.class); } @Test void verifySerializableIsNotEnabled() { - var interfaces = io.quarkiverse.non.serializable.model.Animal.class.getInterfaces(); + var interfaces = org.acme.non.serializable.model.Animal.class.getInterfaces(); assertThat(interfaces).doesNotContain(Serializable.class); } From 4d7108de796c8f454cae6170cf118ec3e1c8e16f Mon Sep 17 00:00:00 2001 From: Richard Alm Date: Wed, 11 Dec 2024 23:24:39 +0100 Subject: [PATCH 5/6] Refactoring based on feedback on PR --- .../OpenApiClientGeneratorWrapper.java | 10 +++++-- client/integration-tests/pom.xml | 2 +- ...SerializableModelRestEasyReactiveTest.java | 29 ------------------- ...icTest.java => SerializableModelTest.java} | 4 +-- 4 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java rename client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/{QuarkusSerializableModelRestEasyClassicTest.java => SerializableModelTest.java} (85%) diff --git a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java index 0e5cbbcbd..12147ece2 100644 --- a/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java +++ b/client/deployment/src/main/java/io/quarkiverse/openapi/generator/deployment/wrapper/OpenApiClientGeneratorWrapper.java @@ -1,6 +1,8 @@ package io.quarkiverse.openapi.generator.deployment.wrapper; -import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.*; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.getSanitizedFileName; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.resolveApiPackage; +import static io.quarkiverse.openapi.generator.deployment.CodegenConfig.resolveModelPackage; import static io.quarkiverse.openapi.generator.deployment.wrapper.QuarkusJavaClientCodegen.QUARKUS_GENERATOR_NAME; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; @@ -9,7 +11,11 @@ import java.io.File; import java.nio.file.Path; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.DefaultGenerator; diff --git a/client/integration-tests/pom.xml b/client/integration-tests/pom.xml index 613f2e354..e1efcf5b3 100644 --- a/client/integration-tests/pom.xml +++ b/client/integration-tests/pom.xml @@ -44,7 +44,7 @@ config-key github without-oidc - serializable-model + serializable-model diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java deleted file mode 100644 index 24d0ff6e9..000000000 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyReactiveTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.quarkiverse.openapi.generator.it; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.Serializable; - -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -@Tag("resteasy-reactive") -class QuarkusSerializableModelRestEasyReactiveTest { - - @Test - void verifySerializableIsEnabled() { - var interfaces = org.acme.serializable.model.Animal.class.getInterfaces(); - - assertThat(interfaces).contains(Serializable.class); - } - - @Test - void verifySerializableIsNotEnabled() { - var interfaces = org.acme.non.serializable.model.Animal.class.getInterfaces(); - - assertThat(interfaces).doesNotContain(Serializable.class); - } -} diff --git a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/SerializableModelTest.java similarity index 85% rename from client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java rename to client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/SerializableModelTest.java index 4f2e20f33..4f1937c15 100644 --- a/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/QuarkusSerializableModelRestEasyClassicTest.java +++ b/client/integration-tests/serializable-model/src/test/java/io/quarkiverse/openapi/generator/it/SerializableModelTest.java @@ -4,14 +4,12 @@ import java.io.Serializable; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; @QuarkusTest -@Tag("resteasy-classic") -class QuarkusSerializableModelRestEasyClassicTest { +class SerializableModelTest { @Test void verifySerializableIsEnabled() { From 447bb461947be44bfac596920252ef221eefeaa0 Mon Sep 17 00:00:00 2001 From: Richard Alm Date: Fri, 13 Dec 2024 00:16:33 +0100 Subject: [PATCH 6/6] Suggestion: Generate equals and hashcode in models. --- .../libraries/microprofile/pojo.qute | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/client/deployment/src/main/resources/templates/libraries/microprofile/pojo.qute b/client/deployment/src/main/resources/templates/libraries/microprofile/pojo.qute index ae5542c1e..f2fc851ea 100644 --- a/client/deployment/src/main/resources/templates/libraries/microprofile/pojo.qute +++ b/client/deployment/src/main/resources/templates/libraries/microprofile/pojo.qute @@ -1,5 +1,6 @@ {@org.openapitools.codegen.CodegenModel m} import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; {#if m.description} /** @@ -135,6 +136,49 @@ public class {m.classname} {#if m.parent}extends {m.parent}{/if}{#if serializabl return sb.toString(); } +{#if m.vars.size > 0} + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + {m.classname} model = ({m.classname}) o; + + {#if m.vars.size == 1} + return Objects.equals({m.vars.0.name}, model.{m.vars.0.name}); + {#else} + {#for v in m.vars} + {#if v_isFirst} + return Objects.equals({v.name}, model.{v.name}) && + {#else if v_isLast} + Objects.equals({v.name}, model.{v.name}); + {#else} + Objects.equals({v.name}, model.{v.name}) && + {/if} + {/for} + {/if} + } +{/if} + +{#if m.vars.size > 0} + @Override + public int hashCode() { + {#if m.vars.size == 1} + return Objects.hash({m.vars.0.name}); + {#else} + {#for v in m.vars} + {#if v_isFirst} + return Objects.hash({v.name}, + {#else if v_isLast} + {v.name}); + {#else} + {v.name}, + {/if} + {/for} + {/if} + } +{/if} + /** * Convert the given object to string with each line indented by 4 spaces * (except the first line).