From 10a1e7c2d5353efec08c258bea34675811ddae71 Mon Sep 17 00:00:00 2001 From: DeaneOC <113348490+DeaneOC@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:07:48 +0100 Subject: [PATCH] Fix #13385 spring json nullable array (#13537) * Fixing to use equalsNullable when nullable set in config for SpringCodeGen * Adding additional test case file * removed print statement from SpringCodeGen * Updated model object * Corrected indentation and removed import * Fixed broken test * Updating sample --- .../languages/AbstractJavaCodegen.java | 20 + .../codegen/languages/JavaClientCodegen.java | 21 +- .../codegen/languages/SpringCodegen.java | 10 +- .../java/spring/SpringCodegenTest.java | 466 ++++++++++-------- .../src/test/resources/bugs/issue_13385.yml | 23 + .../src/test/resources/bugs/issue_13385_2.yml | 23 + .../model/ObjectWithUniqueItems.java | 7 +- 7 files changed, 348 insertions(+), 222 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/bugs/issue_13385.yml create mode 100644 modules/openapi-generator/src/test/resources/bugs/issue_13385_2.yml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java index 2ef252c32197..0814e11b82f2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java @@ -2149,4 +2149,24 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code extensions.add(VendorExtension.X_FIELD_EXTRA_ANNOTATION); return extensions; } + + public boolean isAddNullableImports(CodegenModel cm, boolean addImports, CodegenProperty var) { + if (this.openApiNullable) { + boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable); + // only add JsonNullable and related imports to optional and nullable values + addImports |= isOptionalNullable; + var.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable); + findByName(var.name, cm.readOnlyVars) + .ifPresent(p -> p.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable)); + } + return addImports; + } + public static void addImports(List> imports, CodegenModel cm, Map imports2Classnames) { + for (Map.Entry entry : imports2Classnames.entrySet()) { + cm.imports.add(entry.getKey()); + Map importsItem = new HashMap<>(); + importsItem.put("import", entry.getValue()); + imports.add(importsItem); + } + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java index cedd19cfafb4..c2b5ad4863a7 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java @@ -918,18 +918,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen List> imports = objs.getImports(); for (ModelMap mo : models) { CodegenModel cm = mo.getModel(); - boolean addImports = false; + boolean addNullableImports = false; for (CodegenProperty var : cm.vars) { - if (this.openApiNullable) { - boolean isOptionalNullable = Boolean.FALSE.equals(var.required) && Boolean.TRUE.equals(var.isNullable); - // only add JsonNullable and related imports to optional and nullable values - addImports |= isOptionalNullable; - var.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable); - findByName(var.name, cm.readOnlyVars) - .ifPresent(p -> p.getVendorExtensions().put("x-is-jackson-optional-nullable", isOptionalNullable)); - } - + addNullableImports = isAddNullableImports(cm, addNullableImports, var); if (Boolean.TRUE.equals(var.getVendorExtensions().get("x-enum-as-string"))) { // treat enum string as just string var.datatypeWithEnum = var.dataType; @@ -956,17 +948,12 @@ public class JavaClientCodegen extends AbstractJavaCodegen } - if (addImports) { + if (addNullableImports) { Map imports2Classnames = new HashMap<>(); imports2Classnames.put("JsonNullable", "org.openapitools.jackson.nullable.JsonNullable"); imports2Classnames.put("NoSuchElementException", "java.util.NoSuchElementException"); imports2Classnames.put("JsonIgnore", "com.fasterxml.jackson.annotation.JsonIgnore"); - for (Map.Entry entry : imports2Classnames.entrySet()) { - cm.imports.add(entry.getKey()); - Map importsItem = new HashMap<>(); - importsItem.put("import", entry.getValue()); - imports.add(importsItem); - } + addImports(imports, cm, imports2Classnames); } } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index a076cf99dd64..35a208dd3d72 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -1036,13 +1036,21 @@ public class SpringCodegen extends AbstractJavaCodegen final List> imports = objs.getImports(); for (ModelMap mo : objs.getModels()) { CodegenModel cm = mo.getModel(); - // for enum model + boolean addNullableImports = false; + for (CodegenProperty var : cm.vars) { + addNullableImports = isAddNullableImports(cm, addNullableImports, var); + } if (Boolean.TRUE.equals(cm.isEnum) && cm.allowableValues != null) { cm.imports.add(importMapping.get("JsonValue")); final Map item = new HashMap<>(); item.put("import", importMapping.get("JsonValue")); imports.add(item); } + if (addNullableImports) { + Map imports2Classnames = new HashMap<>(); + imports2Classnames.put("NoSuchElementException", "java.util.NoSuchElementException"); + addImports(imports, cm, imports2Classnames); + } } return objs; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 0d70551f45d5..95e9a7f5a395 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -33,6 +33,7 @@ import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.servers.Server; import io.swagger.v3.parser.core.models.ParseOptions; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -105,52 +106,52 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ZebrasApi.java")) - .assertTypeAnnotations() + .assertTypeAnnotations() .hasSize(4) .containsWithName("Validated") .containsWithName("Generated") .containsWithName("RequestMapping") .containsWithNameAndAttributes("Generated", ImmutableMap.of( - "value", "\"org.openapitools.codegen.languages.SpringCodegen\"" + "value", "\"org.openapitools.codegen.languages.SpringCodegen\"" )) .containsWithNameAndAttributes("Tag", ImmutableMap.of( - "name", "\"zebras\"" + "name", "\"zebras\"" )) - .toType() - .assertMethod("getZebras") + .toType() + .assertMethod("getZebras") .hasReturnType("ResponseEntity") .assertMethodAnnotations() .hasSize(2) .containsWithNameAndAttributes("Operation", ImmutableMap.of("operationId", "\"getZebras\"")) .containsWithNameAndAttributes("RequestMapping", ImmutableMap.of( - "method", "RequestMethod.GET", - "value", "\"/zebras\"" + "method", "RequestMethod.GET", + "value", "\"/zebras\"" )) - .toMethod() - .hasParameter("limit").withType("BigDecimal") - .assertParameterAnnotations() - .containsWithName("Valid") - .containsWithNameAndAttributes("Parameter", ImmutableMap.of("name", "\"limit\"")) - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("required", "false", "value", "\"limit\"")) - .toParameter() - .toMethod() - .hasParameter("animalParams").withType("AnimalParams") - .toMethod() - .commentContainsLines("GET /zebras", "@param limit (optional)") - .bodyContainsLines("return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED)"); + .toMethod() + .hasParameter("limit").withType("BigDecimal") + .assertParameterAnnotations() + .containsWithName("Valid") + .containsWithNameAndAttributes("Parameter", ImmutableMap.of("name", "\"limit\"")) + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("required", "false", "value", "\"limit\"")) + .toParameter() + .toMethod() + .hasParameter("animalParams").withType("AnimalParams") + .toMethod() + .commentContainsLines("GET /zebras", "@param limit (optional)") + .bodyContainsLines("return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED)"); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/model/AnimalParams.java")) - .hasImports("org.springframework.format.annotation.DateTimeFormat") - .hasProperty("born").withType("LocalDate") + .hasImports("org.springframework.format.annotation.DateTimeFormat") + .hasProperty("born").withType("LocalDate") .assertPropertyAnnotations() .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE")) .toProperty() - .toType() - .hasProperty("lastSeen").withType("OffsetDateTime") + .toType() + .hasProperty("lastSeen").withType("OffsetDateTime") .assertPropertyAnnotations() .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")) - .toProperty().toType() - .assertMethod("born", "LocalDate") + .toProperty().toType() + .assertMethod("born", "LocalDate") .bodyContainsLines("this.born = born") .doesNotHaveComment(); } @@ -182,21 +183,21 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ElephantsApi.java")) - .assertMethod("getElephants", "String", "BigDecimal") - .hasParameter("userToken") - .assertParameterAnnotations() - .containsWithNameAndAttributes("CookieValue", ImmutableMap.of("name", "\"userToken\"")); + .assertMethod("getElephants", "String", "BigDecimal") + .hasParameter("userToken") + .assertParameterAnnotations() + .containsWithNameAndAttributes("CookieValue", ImmutableMap.of("name", "\"userToken\"")); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ZebrasApi.java")) - .assertMethod("getZebras", "String") - .hasParameter("userToken") - .assertParameterAnnotations() - .containsWithNameAndAttributes("CookieValue", ImmutableMap.of("name", "\"userToken\"")); + .assertMethod("getZebras", "String") + .hasParameter("userToken") + .assertParameterAnnotations() + .containsWithNameAndAttributes("CookieValue", ImmutableMap.of("name", "\"userToken\"")); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/BirdsApi.java")) - .assertMethod("getBirds", "BigDecimal") - .doesNotHaveParameter("userToken") - .noneOfParameterHasAnnotation("CookieValue"); + .assertMethod("getBirds", "BigDecimal") + .doesNotHaveParameter("userToken") + .noneOfParameterHasAnnotation("CookieValue"); } @Test @@ -292,18 +293,18 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ElephantsApi.java")) - .hasImports("org.springframework.format.annotation.DateTimeFormat") - .assertMethod("getElephants", "LocalDate") - .hasParameter("startDate") - .assertParameterAnnotations() - .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE")); + .hasImports("org.springframework.format.annotation.DateTimeFormat") + .assertMethod("getElephants", "LocalDate") + .hasParameter("startDate") + .assertParameterAnnotations() + .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE")); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ZebrasApi.java")) - .hasImports("org.springframework.format.annotation.DateTimeFormat") - .assertMethod("getZebras", "OffsetDateTime") - .hasParameter("startDateTime") - .assertParameterAnnotations() - .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")); + .hasImports("org.springframework.format.annotation.DateTimeFormat") + .assertMethod("getZebras", "OffsetDateTime") + .hasParameter("startDateTime") + .assertParameterAnnotations() + .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")); } @Test @@ -352,14 +353,14 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ExampleApi.java")) - .assertMethod("exampleApiGet", "String", "Format") + .assertMethod("exampleApiGet", "String", "Format") .hasParameter("query") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"query\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"query\"")) .toParameter().toMethod() .hasParameter("format") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"format\"")); + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"format\"")); } @Test @@ -390,11 +391,11 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ExampleApi.java")) - .assertMethod("exampleApiGet", "OffsetDateTime") - .hasParameter("start") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"start\"")) - .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")); + .assertMethod("exampleApiGet", "OffsetDateTime") + .hasParameter("start") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"start\"")) + .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")); } @Test @@ -519,10 +520,10 @@ public class SpringCodegenTest { generator.opts(input).generate(); JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ExampleApi.java")) - .assertMethod("exampleApiPost", "ExampleApiPostRequest") - .hasParameter("exampleApiPostRequest") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestBody", ImmutableMap.of("required", "false")); + .assertMethod("exampleApiPost", "ExampleApiPostRequest") + .hasParameter("exampleApiPostRequest") + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestBody", ImmutableMap.of("required", "false")); assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ExampleApi.java"), "@RequestBody(required = false"); @@ -565,16 +566,16 @@ public class SpringCodegenTest { // Check that the delegate handles the array JavaFileAssert.assertThat(files.get("MultipartArrayApiDelegate.java")) - .assertMethod("multipartArray", "List") - .hasParameter("files").withType("List"); + .assertMethod("multipartArray", "List") + .hasParameter("files").withType("List"); // Check that the api handles the array JavaFileAssert.assertThat(files.get("MultipartArrayApi.java")) - .assertMethod("multipartArray", "List") - .hasParameter("files").withType("List") - .assertParameterAnnotations() - .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"Many files\"")) - .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"files\"", "required", "false")); + .assertMethod("multipartArray", "List") + .hasParameter("files").withType("List") + .assertParameterAnnotations() + .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"Many files\"")) + .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"files\"", "required", "false")); // UPDATE: the following test has been ignored due to https://github.com/OpenAPITools/openapi-generator/pull/11081/ // We will contact the contributor of the following test to see if the fix will break their use cases and @@ -585,25 +586,25 @@ public class SpringCodegenTest { // Check that the api handles the single file JavaFileAssert.assertThat(files.get("MultipartSingleApi.java")) - .assertMethod("multipartSingle", "MultipartFile") - .hasParameter("file").withType("MultipartFile") - .assertParameterAnnotations() - .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"One file\"")) - .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"file\"", "required", "false")); + .assertMethod("multipartSingle", "MultipartFile") + .hasParameter("file").withType("MultipartFile") + .assertParameterAnnotations() + .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"One file\"")) + .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"file\"", "required", "false")); // Check that api validates mixed multipart request JavaFileAssert.assertThat(files.get("MultipartMixedApi.java")) - .assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker") + .assertMethod("multipartMixed", "MultipartMixedStatus", "MultipartFile", "MultipartMixedRequestMarker") .hasParameter("status").withType("MultipartMixedStatus") .assertParameterAnnotations() .containsWithName("Valid") .containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"\"")) .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"status\"", "required", "true")) - .toParameter().toMethod() + .toParameter().toMethod() .hasParameter("file").withType("MultipartFile") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"file\"", "required", "true")) - .toParameter().toMethod() + .toParameter().toMethod() .hasParameter("marker").withType("MultipartMixedRequestMarker") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("value", "\"marker\"", "required", "false")); @@ -652,10 +653,10 @@ public class SpringCodegenTest { // Check that the api handles the array and the file final File multipartApi = files.get("MultipartApi.java"); assertFileContains(multipartApi.toPath(), - "List files", - "MultipartFile file"); + "List files", + "MultipartFile file"); } - + @Test public void testRequestMappingAnnotation() throws IOException { final SpringCodegen codegen = new SpringCodegen(); @@ -861,12 +862,14 @@ public class SpringCodegenTest { generator.opts(input).generate(); assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/GetApi.java"), - "@RequestParam(value = \"testParameter1\", required = false, defaultValue = \"BAR\")", - "@RequestParam(value = \"TestParameter2\", required = false, defaultValue = \"BAR\")"); + "@RequestParam(value = \"testParameter1\", required = false, defaultValue = \"BAR\")", + "@RequestParam(value = \"TestParameter2\", required = false, defaultValue = \"BAR\")"); } - /**Define documentation providers to test */ + /** + * Define documentation providers to test + */ private final static String SPRINGFOX = "springfox"; private final static String SPRINGFOX_DESTINATIONFILE = "SpringFoxConfiguration.java"; private final static String SPRINGFOX_TEMPLATEFILE = "openapiDocumentationConfig.mustache"; @@ -892,7 +895,7 @@ public class SpringCodegenTest { testConfigFileCommon(SPRINGDOC, SPRINGDOC_DESTINATIONFILE, SPRINGDOC_TEMPLATEFILE); } - private void testConfigFileCommon(String documentationProvider, String destinationFile, String templateFileName){ + private void testConfigFileCommon(String documentationProvider, String destinationFile, String templateFileName) { final SpringCodegen codegen = new SpringCodegen(); codegen.additionalProperties().put(DOCUMENTATION_PROVIDER, documentationProvider); codegen.additionalProperties().put(SpringCodegen.INTERFACE_ONLY, false); @@ -988,7 +991,7 @@ public class SpringCodegenTest { output.deleteOnExit(); String outputPath = output.getAbsolutePath().replace('\\', '/'); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/3_0/issue_5381.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/3_0/issue_5381.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); @@ -1026,7 +1029,7 @@ public class SpringCodegenTest { output.deleteOnExit(); String outputPath = output.getAbsolutePath().replace('\\', '/'); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/3_0/oneof_polymorphism_and_inheritance.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); @@ -1088,7 +1091,7 @@ public class SpringCodegenTest { String outputPath = output.getAbsolutePath().replace('\\', '/'); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_11464.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_11464.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); @@ -1112,23 +1115,23 @@ public class SpringCodegenTest { @DataProvider public Object[][] issue11464TestCases() { - return new Object[][] { - { DocumentationProviderFeatures.DocumentationProvider.SPRINGDOC.name(), (Consumer) outputPath -> { - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/NoneApi.java"), - "@Operation( operationId = \"getNone\", summary = \"No Tag\", responses = {"); - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/SingleApi.java"), - "@Operation( operationId = \"getSingleTag\", summary = \"Single Tag\", tags = { \"tag1\" }, responses = {"); - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/MultipleApi.java"), - "@Operation( operationId = \"getMultipleTags\", summary = \"Multiple Tags\", tags = { \"tag1\", \"tag2\" }, responses = {"); - }}, - { DocumentationProviderFeatures.DocumentationProvider.SPRINGFOX.name(), (Consumer) outputPath -> { - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/NoneApi.java"), - "@ApiOperation( value = \"No Tag\", nickname = \"getNone\", notes = \"\", response = "); - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/SingleApi.java"), - "@ApiOperation( tags = { \"tag1\" }, value = \"Single Tag\", nickname = \"getSingleTag\", notes = \"\", response = "); - assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/MultipleApi.java"), - "@ApiOperation( tags = { \"tag1\", \"tag2\" }, value = \"Multiple Tags\", nickname = \"getMultipleTags\", notes = \"\", response = "); - }}, + return new Object[][]{ + {DocumentationProviderFeatures.DocumentationProvider.SPRINGDOC.name(), (Consumer) outputPath -> { + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/NoneApi.java"), + "@Operation( operationId = \"getNone\", summary = \"No Tag\", responses = {"); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/SingleApi.java"), + "@Operation( operationId = \"getSingleTag\", summary = \"Single Tag\", tags = { \"tag1\" }, responses = {"); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/MultipleApi.java"), + "@Operation( operationId = \"getMultipleTags\", summary = \"Multiple Tags\", tags = { \"tag1\", \"tag2\" }, responses = {"); + }}, + {DocumentationProviderFeatures.DocumentationProvider.SPRINGFOX.name(), (Consumer) outputPath -> { + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/NoneApi.java"), + "@ApiOperation( value = \"No Tag\", nickname = \"getNone\", notes = \"\", response = "); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/SingleApi.java"), + "@ApiOperation( tags = { \"tag1\" }, value = \"Single Tag\", nickname = \"getSingleTag\", notes = \"\", response = "); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/api/MultipleApi.java"), + "@ApiOperation( tags = { \"tag1\", \"tag2\" }, value = \"Multiple Tags\", nickname = \"getMultipleTags\", notes = \"\", response = "); + }}, }; } @@ -1148,7 +1151,7 @@ public class SpringCodegenTest { String outputPath = output.getAbsolutePath().replace('\\', '/'); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/3_0/spring/issue_11323.yml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/3_0/spring/issue_11323.yml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); @@ -1168,7 +1171,7 @@ public class SpringCodegenTest { generator.opts(input).generate(); assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Address.java"), - "@JsonValue", "import com.fasterxml.jackson.annotation.JsonValue;"); + "@JsonValue", "import com.fasterxml.jackson.annotation.JsonValue;"); } @Test @@ -1178,7 +1181,7 @@ public class SpringCodegenTest { String outputPath = output.getAbsolutePath().replace('\\', '/'); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/3_0/petstore.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/3_0/petstore.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); @@ -1202,10 +1205,10 @@ public class SpringCodegenTest { for (File modelPath : generatedModels) { JavaFileAssert.assertThat(modelPath) - .assertTypeAnnotations() - .containsWithName("custom.Annotation") - .containsWithName("path.Annotation2") - .containsWithNameAndAttributes("path.Annotation", ImmutableMap.of("param1", "\"test1\"", "param2", "3")); + .assertTypeAnnotations() + .containsWithName("custom.Annotation") + .containsWithName("path.Annotation2") + .containsWithNameAndAttributes("path.Annotation", ImmutableMap.of("param1", "\"test1\"", "param2", "3")); } } @@ -1215,70 +1218,70 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/3_0/issue_8535.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/3_0/issue_8535.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true"); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("TestHeadersApi.java")) - .assertMethod("headersTest") + .assertMethod("headersTest") .hasParameter("headerNumber").withType("BigDecimal") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"11.2\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"11.2\"")) .toParameter().toMethod() .hasParameter("headerString").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\"")) .toParameter().toMethod() .hasParameter("headerStringWrapped").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\"")) .toParameter().toMethod() .hasParameter("headerStringQuotes").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) .toParameter().toMethod() .hasParameter("headerStringQuotesWrapped").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) .toParameter().toMethod() .hasParameter("headerBoolean").withType("Boolean") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"true\"")); + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestHeader", ImmutableMap.of("defaultValue", "\"true\"")); JavaFileAssert.assertThat(files.get("TestQueryParamsApi.java")) - .assertMethod("queryParamsTest") + .assertMethod("queryParamsTest") .hasParameter("queryNumber").withType("BigDecimal") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"11.2\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"11.2\"")) .toParameter().toMethod() .hasParameter("queryString").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\"")) .toParameter().toMethod() .hasParameter("queryStringWrapped").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\"")) .toParameter().toMethod() .hasParameter("queryStringQuotes").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) .toParameter().toMethod() .hasParameter("queryStringQuotesWrapped").withType("String") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"qwerty\\\"with quotes\\\" test\"")) .toParameter().toMethod() .hasParameter("queryBoolean").withType("Boolean") - .assertParameterAnnotations() - .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"true\"")); + .assertParameterAnnotations() + .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"true\"")); } @Test @@ -1317,7 +1320,7 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_11897.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_11897.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setLibrary(SPRING_BOOT); codegen.setOutputDir(output.getAbsolutePath()); @@ -1330,25 +1333,25 @@ public class SpringCodegenTest { codegen.additionalProperties().put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("MetadataApi.java")) - .assertMethod("getWithArrayOfObjects").hasReturnType("ResponseEntity>") - .toFileAssert() - .assertMethod("getWithArrayOfString").hasReturnType("ResponseEntity>") - .toFileAssert() - .assertMethod("getWithSetOfObjects").hasReturnType("ResponseEntity>") - .toFileAssert() - .assertMethod("getWithSetOfStrings").hasReturnType("ResponseEntity>") - .toFileAssert() - .assertMethod("getWithMapOfObjects").hasReturnType("ResponseEntity>") - .toFileAssert() - .assertMethod("getWithMapOfStrings").hasReturnType("ResponseEntity>"); + .assertMethod("getWithArrayOfObjects").hasReturnType("ResponseEntity>") + .toFileAssert() + .assertMethod("getWithArrayOfString").hasReturnType("ResponseEntity>") + .toFileAssert() + .assertMethod("getWithSetOfObjects").hasReturnType("ResponseEntity>") + .toFileAssert() + .assertMethod("getWithSetOfStrings").hasReturnType("ResponseEntity>") + .toFileAssert() + .assertMethod("getWithMapOfObjects").hasReturnType("ResponseEntity>") + .toFileAssert() + .assertMethod("getWithMapOfStrings").hasReturnType("ResponseEntity>"); } @Test @@ -1357,7 +1360,7 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_11957.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_11957.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setLibrary(SPRING_BOOT); codegen.setOutputDir(output.getAbsolutePath()); @@ -1370,30 +1373,30 @@ public class SpringCodegenTest { codegen.additionalProperties().put(CodegenConstants.SERIALIZATION_LIBRARY, "jackson"); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("SearchApi.java")) - .assertMethod("defaultList") + .assertMethod("defaultList") .hasParameter("orderBy") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"updatedAt:DESC,createdAt:DESC\"")) - .toParameter().toMethod().toFileAssert() - .assertMethod("defaultSet") + .toParameter().toMethod().toFileAssert() + .assertMethod("defaultSet") .hasParameter("orderBy") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"updatedAt:DESC,createdAt:DESC\"")) - .toParameter().toMethod().toFileAssert() - .assertMethod("emptyDefaultList") + .toParameter().toMethod().toFileAssert() + .assertMethod("emptyDefaultList") .hasParameter("orderBy") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"\"")) - .toParameter().toMethod().toFileAssert() - .assertMethod("emptyDefaultSet") + .toParameter().toMethod().toFileAssert() + .assertMethod("emptyDefaultSet") .hasParameter("orderBy") .assertParameterAnnotations() .containsWithNameAndAttributes("RequestParam", ImmutableMap.of("defaultValue", "\"\"")); @@ -1405,21 +1408,21 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_12494.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_12494.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setOutputDir(output.getAbsolutePath()); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("ChildClass.java")) - .assertMethod("putSomeMapItem") - .bodyContainsLines("super.putSomeMapItem(key, someMapItem);"); + .assertMethod("putSomeMapItem") + .bodyContainsLines("super.putSomeMapItem(key, someMapItem);"); } @Test @@ -1428,22 +1431,22 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_11731.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_11731.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setLibrary(SPRING_BOOT); codegen.setOutputDir(output.getAbsolutePath()); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("CustomersApi.java")) - .assertMethod("getAllUsingGET1") - .bodyContainsLines("if (mediaType.isCompatibleWith(MediaType.valueOf(\"application/hal+json\"))) {"); + .assertMethod("getAllUsingGET1") + .bodyContainsLines("if (mediaType.isCompatibleWith(MediaType.valueOf(\"application/hal+json\"))) {"); } @Test @@ -1452,27 +1455,27 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_12457.yaml", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_12457.yaml", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setLibrary(SPRING_BOOT); codegen.setOutputDir(output.getAbsolutePath()); codegen.additionalProperties().put(SpringCodegen.USE_TAGS, "true"); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("UsersApi.java")) - .assertMethod("wildcardSubTypeForContentType") - .assertMethodAnnotations() - .containsWithNameAndAttributes("RequestMapping", ImmutableMap.of( - "produces", "{ \"application/json\", \"application/*\" }", - "consumes", "{ \"application/octet-stream\", \"application/*\" }" - )); + .assertMethod("wildcardSubTypeForContentType") + .assertMethodAnnotations() + .containsWithNameAndAttributes("RequestMapping", ImmutableMap.of( + "produces", "{ \"application/json\", \"application/*\" }", + "consumes", "{ \"application/octet-stream\", \"application/*\" }" + )); } @Test @@ -1496,8 +1499,8 @@ public class SpringCodegenTest { String jsonTypeInfo = "@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = \"type\", visible = true)"; String jsonSubType = "@JsonSubTypes({\n" + - " @JsonSubTypes.Type(value = Cat.class, name = \"cat\")" + - "})"; + " @JsonSubTypes.Type(value = Cat.class, name = \"cat\")" + + "})"; assertFileContains(Paths.get(output.getAbsolutePath() + "/src/main/java/org/openapitools/model/Pet.java"), jsonTypeInfo, jsonSubType); } @@ -1507,7 +1510,7 @@ public class SpringCodegenTest { output.deleteOnExit(); OpenAPI openAPI = new OpenAPIParser() - .readLocation("src/test/resources/bugs/issue_7125.json", null, new ParseOptions()).getOpenAPI(); + .readLocation("src/test/resources/bugs/issue_7125.json", null, new ParseOptions()).getOpenAPI(); SpringCodegen codegen = new SpringCodegen(); codegen.setLibrary(SPRING_BOOT); codegen.setOutputDir(output.getAbsolutePath()); @@ -1515,32 +1518,93 @@ public class SpringCodegenTest { codegen.additionalProperties().put(BeanValidationFeatures.USE_BEANVALIDATION, "true"); ClientOptInput input = new ClientOptInput() - .openAPI(openAPI) - .config(codegen); + .openAPI(openAPI) + .config(codegen); DefaultGenerator generator = new DefaultGenerator(); Map files = generator.opts(input).generate().stream() - .collect(Collectors.toMap(File::getName, Function.identity())); + .collect(Collectors.toMap(File::getName, Function.identity())); JavaFileAssert.assertThat(files.get("SomeMethodApi.java")) - .printFileContent() - .assertMethod("methodWithValidation") - .hasParameter("headerOne") + .printFileContent() + .assertMethod("methodWithValidation") + .hasParameter("headerOne") .assertParameterAnnotations() .containsWithName("RequestHeader") .containsWithName("NotNull") .containsWithNameAndAttributes("Size", ImmutableMap.of( - "min", "1", - "max", "10" + "min", "1", + "max", "10" )) .containsWithNameAndAttributes("Pattern", ImmutableMap.of("regexp", "\"\\\\d+\"")) - .toParameter() - .toMethod() - .hasParameter("headerTwo") + .toParameter() + .toMethod() + .hasParameter("headerTwo") .assertParameterAnnotations() .containsWithName("RequestHeader") .containsWithName("NotNull") .containsWithNameAndAttributes("Min", ImmutableMap.of("value", "500")) .containsWithNameAndAttributes("Max", ImmutableMap.of("value", "10000")); } + + @Test + public void shouldUseEqualsNullableForArrayWhenSetInConfig_issue13385() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_13385.yml", null, new ParseOptions()).getOpenAPI(); + SpringCodegen codegen = new SpringCodegen(); + codegen.setLibrary(SPRING_BOOT); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(SpringCodegen.INTERFACE_ONLY, "true"); + codegen.additionalProperties().put(SpringCodegen.USE_BEANVALIDATION, "true"); + codegen.additionalProperties().put(SpringCodegen.PERFORM_BEANVALIDATION, "true"); + codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.model"); + codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.controller"); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + Map files = generator.opts(input).generate().stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + JavaFileAssert.assertThat(files.get("TestObject.java")) + .printFileContent() + .assertMethod("equals") + .bodyContainsLines("return equalsNullable(this.picture, testObject.picture);"); + + } + + @Test + public void shouldNotUseEqualsNullableForArrayWhenNotSetInConfig_issue13385() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_13385_2.yml", null, new ParseOptions()).getOpenAPI(); + SpringCodegen codegen = new SpringCodegen(); + codegen.setLibrary(SPRING_BOOT); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(SpringCodegen.INTERFACE_ONLY, "true"); + codegen.additionalProperties().put(SpringCodegen.USE_BEANVALIDATION, "true"); + codegen.additionalProperties().put(SpringCodegen.PERFORM_BEANVALIDATION, "true"); + codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.model"); + codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.controller"); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + Map files = generator.opts(input).generate().stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + JavaFileAssert.assertThat(files.get("TestObject.java")) + .printFileContent() + .assertMethod("equals") + .bodyContainsLines("return Arrays.equals(this.picture, testObject.picture);"); + } } diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_13385.yml b/modules/openapi-generator/src/test/resources/bugs/issue_13385.yml new file mode 100644 index 000000000000..2940b410aa3b --- /dev/null +++ b/modules/openapi-generator/src/test/resources/bugs/issue_13385.yml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + version: 1.0.0 + description: Specification to reproduce nullable issue with Array + title: ArrayNullableTest Api +paths: + /arrayNullable: + get: + summary: dummy + operationId: dummy + responses: + '200': + description: OK + +components: + schemas: + TestObject: + type: object + properties: + picture: + type: string + format: byte + nullable: true \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_13385_2.yml b/modules/openapi-generator/src/test/resources/bugs/issue_13385_2.yml new file mode 100644 index 000000000000..25b8bbc81272 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/bugs/issue_13385_2.yml @@ -0,0 +1,23 @@ +openapi: 3.0.3 +info: + version: 1.0.0 + description: Specification to reproduce nullable issue with Array + title: ArrayNullableTest Api +paths: + /arrayNullable: + get: + summary: dummy + operationId: dummy + responses: + '200': + description: OK + +components: + schemas: + TestObject: + type: object + properties: + picture: + type: string + format: byte + nullable: false \ No newline at end of file diff --git a/samples/server/petstore/spring-boot-nullable-set/src/main/java/org/openapitools/model/ObjectWithUniqueItems.java b/samples/server/petstore/spring-boot-nullable-set/src/main/java/org/openapitools/model/ObjectWithUniqueItems.java index 190950d867d5..a322f8ae1564 100644 --- a/samples/server/petstore/spring-boot-nullable-set/src/main/java/org/openapitools/model/ObjectWithUniqueItems.java +++ b/samples/server/petstore/spring-boot-nullable-set/src/main/java/org/openapitools/model/ObjectWithUniqueItems.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.Set; import org.openapitools.jackson.nullable.JsonNullable; import org.springframework.format.annotation.DateTimeFormat; +import java.util.NoSuchElementException; import org.openapitools.jackson.nullable.JsonNullable; import java.time.OffsetDateTime; import javax.validation.Valid; @@ -210,9 +211,9 @@ public class ObjectWithUniqueItems { return false; } ObjectWithUniqueItems objectWithUniqueItems = (ObjectWithUniqueItems) o; - return Objects.equals(this.nullSet, objectWithUniqueItems.nullSet) && + return equalsNullable(this.nullSet, objectWithUniqueItems.nullSet) && Objects.equals(this.notNullSet, objectWithUniqueItems.notNullSet) && - Objects.equals(this.nullList, objectWithUniqueItems.nullList) && + equalsNullable(this.nullList, objectWithUniqueItems.nullList) && Objects.equals(this.notNullList, objectWithUniqueItems.notNullList) && Objects.equals(this.notNullDateField, objectWithUniqueItems.notNullDateField) && Objects.equals(this.nullDateField, objectWithUniqueItems.nullDateField); @@ -224,7 +225,7 @@ public class ObjectWithUniqueItems { @Override public int hashCode() { - return Objects.hash(nullSet, notNullSet, nullList, notNullList, notNullDateField, nullDateField); + return Objects.hash(hashCodeNullable(nullSet), notNullSet, hashCodeNullable(nullList), notNullList, notNullDateField, nullDateField); } private static int hashCodeNullable(JsonNullable a) {