From ec1f90e2d844dbab316eec03f0befcb22e094f66 Mon Sep 17 00:00:00 2001 From: Stephan Schnabel Date: Mon, 25 Dec 2023 10:37:21 +0100 Subject: [PATCH] Fix hashCode for additionalProperties, fix #336 (#347) * Add test case for #336 * Fix hashCode for `additionalProperties`, fix #336 --- gen/main/java/issue/_336/ServiceScopes.java | 91 +++++++++++++++++++ .../resources/Micronaut/modelPojo.mustache | 2 +- .../codegen/languages/IssueCodegenTest.java | 6 ++ src/test/resources/openapi/issue-336.yaml | 18 ++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 gen/main/java/issue/_336/ServiceScopes.java create mode 100644 src/test/resources/openapi/issue-336.yaml diff --git a/gen/main/java/issue/_336/ServiceScopes.java b/gen/main/java/issue/_336/ServiceScopes.java new file mode 100644 index 00000000..b8a5a8a0 --- /dev/null +++ b/gen/main/java/issue/_336/ServiceScopes.java @@ -0,0 +1,91 @@ +package issue._336; + +@jakarta.annotation.Generated("org.openapitools.codegen.languages.MicronautCodegen") +@io.micronaut.serde.annotation.Serdeable +public class ServiceScopes { + + @com.fasterxml.jackson.annotation.JsonProperty("foo") + @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) + private java.lang.String foo; + + @com.fasterxml.jackson.annotation.JsonProperty("bar") + @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) + private java.lang.String bar; + + private java.util.Map additionalProperties; + + // methods + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + ServiceScopes other = (ServiceScopes) object; + return java.util.Objects.equals(this.additionalProperties, other.additionalProperties) + && java.util.Objects.equals(foo, other.foo) + && java.util.Objects.equals(bar, other.bar); + } + + @Override + public int hashCode() { + return java.util.Objects.hash(this.additionalProperties, foo, bar); + } + + @Override + public java.lang.String toString() { + return new java.lang.StringBuilder() + .append("ServiceScopes[") + .append("additionalProperties=").append(this.additionalProperties) + .append("foo=").append(foo).append(",") + .append("bar=").append(bar) + .append("]") + .toString(); + } + + // fluent + + public ServiceScopes foo(java.lang.String newFoo) { + this.foo = newFoo; + return this; + } + + public ServiceScopes bar(java.lang.String newBar) { + this.bar = newBar; + return this; + } + + @com.fasterxml.jackson.annotation.JsonAnyGetter + public java.util.Map getAdditionalProperties() { + return additionalProperties; + } + + @com.fasterxml.jackson.annotation.JsonAnySetter + public void setAdditionalProperties(java.lang.String propertyKey, java.lang.String value) { + if (this.additionalProperties == null) { + this.additionalProperties = new java.util.HashMap<>(); + } + this.additionalProperties.put(propertyKey, value); + } + + // getter/setter + + public java.lang.String getFoo() { + return foo; + } + + public void setFoo(java.lang.String newFoo) { + this.foo = newFoo; + } + + public java.lang.String getBar() { + return bar; + } + + public void setBar(java.lang.String newBar) { + this.bar = newBar; + } +} diff --git a/src/main/resources/Micronaut/modelPojo.mustache b/src/main/resources/Micronaut/modelPojo.mustache index b24fd590..a7fb5a49 100644 --- a/src/main/resources/Micronaut/modelPojo.mustache +++ b/src/main/resources/Micronaut/modelPojo.mustache @@ -39,7 +39,7 @@ public{{#sealed}}{{#interfaceModels}} final{{/interfaceModels}}{{/sealed}} class @Override public int hashCode() { - return java.util.Objects.hash({{#vendorExtensions.additionalPropertiesMap}}this.additionalProperties{{#vars}}, {{/vars}}{{/vendorExtensions.additionalPropertiesMap}}{{^allVars}}{{#discriminator}}{{discriminator.propertyGetter}}(){{/discriminator}}{{/allVars}}{{#allVars}}{{^isFile}}{{^isByteArray}}{{name}}{{/isByteArray}}{{/isFile}}{{#isByteArray}}java.util.Arrays.hashCode({{name}}){{/isByteArray}}{{#isFile}}java.util.Arrays.hashCode({{name}}){{/isFile}}{{^-last}}, {{/-last}}{{#-last}}{{#discriminator}}, {{discriminator.propertyGetter}}(){{/discriminator}}{{/-last}}{{/allVars}}); + return java.util.Objects.hash({{#vendorExtensions.additionalPropertiesMap}}this.additionalProperties{{#hasVars}}, {{/hasVars}}{{/vendorExtensions.additionalPropertiesMap}}{{^allVars}}{{#discriminator}}{{discriminator.propertyGetter}}(){{/discriminator}}{{/allVars}}{{#allVars}}{{^isFile}}{{^isByteArray}}{{name}}{{/isByteArray}}{{/isFile}}{{#isByteArray}}java.util.Arrays.hashCode({{name}}){{/isByteArray}}{{#isFile}}java.util.Arrays.hashCode({{name}}){{/isFile}}{{^-last}}, {{/-last}}{{#-last}}{{#discriminator}}, {{discriminator.propertyGetter}}(){{/discriminator}}{{/-last}}{{/allVars}}); } @Override diff --git a/src/test/java/org/openapitools/codegen/languages/IssueCodegenTest.java b/src/test/java/org/openapitools/codegen/languages/IssueCodegenTest.java index 0f19c7d5..bfae9f51 100644 --- a/src/test/java/org/openapitools/codegen/languages/IssueCodegenTest.java +++ b/src/test/java/org/openapitools/codegen/languages/IssueCodegenTest.java @@ -26,6 +26,12 @@ void modelWithSuffix() { generate(configurator("src/test/resources/openapi/issue-318.yaml", "issue._318").setModelNameSuffix("Dto")); } + @DisplayName("model with additional properties and multiple properties generate invalid hashcode/equals") + @Test + void modelWithAdditionapPropertiesAndMultipleProperties() { + generate(configurator("src/test/resources/openapi/issue-336.yaml", "issue._336").setGenerateAliasAsModel(true)); + } + static void generate(CodegenConfigurator configurator) { var gen = new DefaultGenerator(); gen.setGenerateMetadata(false); diff --git a/src/test/resources/openapi/issue-336.yaml b/src/test/resources/openapi/issue-336.yaml new file mode 100644 index 00000000..9cd6399b --- /dev/null +++ b/src/test/resources/openapi/issue-336.yaml @@ -0,0 +1,18 @@ +openapi: 3.0.3 +info: + title: Spec for + version: "1" +paths: {} +components: + schemas: + ServiceScopes: + type: object + properties: + foo: + type: string + bar: + type: string + additionalProperties: + $ref: "#/components/schemas/ServiceScopesEntry" + ServiceScopesEntry: + type: string