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 58f7d0e1f226..abc65fe56aa8 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 @@ -662,9 +662,10 @@ public void processOpts() { typeMapping.put("date", "LocalDate"); importMapping.put("LocalDate", "java.time.LocalDate"); importMapping.put("LocalTime", "java.time.LocalTime"); + typeMapping.put("date-time-local", "LocalDateTime"); + importMapping.put("LocalDateTime", "java.time.LocalDateTime"); if ("java8-localdatetime".equals(dateLibrary)) { typeMapping.put("DateTime", "LocalDateTime"); - importMapping.put("LocalDateTime", "java.time.LocalDateTime"); } else { typeMapping.put("DateTime", "OffsetDateTime"); importMapping.put("OffsetDateTime", "java.time.OffsetDateTime"); @@ -1411,6 +1412,13 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) { return "URI.create(\"" + escapeText(String.valueOf(schema.getDefault())) + "\")"; } return null; + } else if (ModelUtils.isDateTimeLocalSchema(schema)) { + if (schema.getDefault() != null) { + if ("java8".equals(getDateLibrary())) { + return String.format(Locale.ROOT, "LocalDateTime.parse(\"%s\")", String.valueOf(schema.getDefault())); + } + } + return null; } else if (ModelUtils.isStringSchema(schema)) { if (schema.getDefault() != null) { String _default; @@ -1493,6 +1501,10 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) { value.asText(), "java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault())"); } + } else if(ModelUtils.isDateTimeLocalSchema(propertySchema)) { + if("java8".equals(getDateLibrary())) { + defaultPropertyExpression = String.format(Locale.ROOT, "java.time.LocalDateTime.parse(\"%s\")", value.asText()); + } } else if(ModelUtils.isUUIDSchema(propertySchema)) { defaultPropertyExpression = "java.util.UUID.fromString(\"" + value.asText() + "\")"; } else if(ModelUtils.isStringSchema(propertySchema)) { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index 84d8cf484f73..a6b082fdf68f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -696,6 +696,12 @@ public static boolean isDateTimeSchema(Schema schema) { && SchemaTypeUtil.DATE_TIME_FORMAT.equals(schema.getFormat())); } + public static boolean isDateTimeLocalSchema(Schema schema) { + // format: date-time-local, see https://spec.openapis.org/registry/format/date-time-local.html + return (SchemaTypeUtil.STRING_TYPE.equals(getType(schema)) + && "date-time-local".equals(schema.getFormat())); + } + public static boolean isPasswordSchema(Schema schema) { return (schema instanceof PasswordSchema) || // double diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/AbstractJavaCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/AbstractJavaCodegenTest.java index 0de76c2eed8a..261746e4b14c 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/AbstractJavaCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/AbstractJavaCodegenTest.java @@ -531,6 +531,15 @@ public void toDefaultValueDateTimeLegacyTest() { // dateLibrary <> java8 Assert.assertEquals(defaultValue, "1984-12-19T03:39:57-09:00"); + + // Test default value for date-time-local format + StringSchema dateTimeLocalSchema = new StringSchema(); + dateTimeLocalSchema.setFormat("date-time-local"); + dateTimeLocalSchema.setDefault("2007-12-03T10:15:30"); + defaultValue = codegen.toDefaultValue(dateTimeLocalSchema); + + // dateLibrary <> java8, should return null + Assert.assertNull(defaultValue); } @Test @@ -593,6 +602,13 @@ public void toDefaultValueTest() { numberSchema.setFormat("double"); defaultValue = codegen.toDefaultValue(codegen.fromProperty("", schema), numberSchema); Assert.assertEquals(defaultValue, doubleValue + "d"); + + // Test default value for date-time-local format + StringSchema dateTimeLocalSchema = new StringSchema(); + dateTimeLocalSchema.setFormat("date-time-local"); + dateTimeLocalSchema.setDefault("2007-12-03T10:15:30"); + defaultValue = codegen.toDefaultValue(codegen.fromProperty("", dateTimeLocalSchema), dateTimeLocalSchema); + Assert.assertEquals(defaultValue, "LocalDateTime.parse(\"2007-12-03T10:15:30\")"); } @Test 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 6dc57b29ad10..f97fb5eee587 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 @@ -381,6 +381,35 @@ public void generateFormatForDateAndDateTimeQueryParam() throws IOException { .containsWithNameAndAttributes("DateTimeFormat", ImmutableMap.of("iso", "DateTimeFormat.ISO.DATE_TIME")); } + @Test + public void generateLocalDateTimeForDateTimeLocalFormat() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/3_0/spring/date-time-parameter-types-for-testing.yml", null, new ParseOptions()).getOpenAPI(); + + SpringCodegen codegen = new SpringCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false"); + generator.setGenerateMetadata(false); + generator.opts(input).generate(); + + JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Pet.java")) + .hasImports("java.time.LocalDateTime") + .assertProperty("adoptionDate").withType("LocalDateTime"); + } + @Test public void interfaceDefaultImplDisableWithResponseWrapper() { final SpringCodegen codegen = new SpringCodegen(); diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/date-time-parameter-types-for-testing.yml b/modules/openapi-generator/src/test/resources/3_0/spring/date-time-parameter-types-for-testing.yml index 535d152fc96e..ea5873285ec5 100644 --- a/modules/openapi-generator/src/test/resources/3_0/spring/date-time-parameter-types-for-testing.yml +++ b/modules/openapi-generator/src/test/resources/3_0/spring/date-time-parameter-types-for-testing.yml @@ -102,3 +102,7 @@ components: type: string format: date default: '2021-01-01' + adoptionDate: + type: string + format: date-time-local + default: '2007-12-03T10:15:30' \ No newline at end of file diff --git a/samples/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java b/samples/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java index abb5ef9adbf5..32c8fedcfbaf 100644 --- a/samples/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java +++ b/samples/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.lang.Nullable; @@ -40,6 +41,8 @@ public class Pet { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate dateOfBirth = LocalDate.parse("2021-01-01"); + private LocalDateTime adoptionDate = LocalDateTime.parse("2007-12-03T10:15:30"); + public Pet() { super(); } @@ -177,6 +180,27 @@ public void setDateOfBirth(LocalDate dateOfBirth) { this.dateOfBirth = dateOfBirth; } + public Pet adoptionDate(LocalDateTime adoptionDate) { + this.adoptionDate = adoptionDate; + return this; + } + + /** + * Get adoptionDate + * @return adoptionDate + */ + @Valid + @Schema(name = "adoptionDate", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("adoptionDate") + public LocalDateTime getAdoptionDate() { + return adoptionDate; + } + + @JsonProperty("adoptionDate") + public void setAdoptionDate(LocalDateTime adoptionDate) { + this.adoptionDate = adoptionDate; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -191,12 +215,13 @@ public boolean equals(Object o) { Objects.equals(this.happy, pet.happy) && Objects.equals(this.price, pet.price) && Objects.equals(this.lastFeed, pet.lastFeed) && - Objects.equals(this.dateOfBirth, pet.dateOfBirth); + Objects.equals(this.dateOfBirth, pet.dateOfBirth) && + Objects.equals(this.adoptionDate, pet.adoptionDate); } @Override public int hashCode() { - return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth); + return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, adoptionDate); } @Override @@ -209,6 +234,7 @@ public String toString() { sb.append(" price: ").append(toIndentedString(price)).append("\n"); sb.append(" lastFeed: ").append(toIndentedString(lastFeed)).append("\n"); sb.append(" dateOfBirth: ").append(toIndentedString(dateOfBirth)).append("\n"); + sb.append(" adoptionDate: ").append(toIndentedString(adoptionDate)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/samples/openapi3/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java b/samples/openapi3/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java index abb5ef9adbf5..32c8fedcfbaf 100644 --- a/samples/openapi3/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java +++ b/samples/openapi3/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.lang.Nullable; @@ -40,6 +41,8 @@ public class Pet { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) private LocalDate dateOfBirth = LocalDate.parse("2021-01-01"); + private LocalDateTime adoptionDate = LocalDateTime.parse("2007-12-03T10:15:30"); + public Pet() { super(); } @@ -177,6 +180,27 @@ public void setDateOfBirth(LocalDate dateOfBirth) { this.dateOfBirth = dateOfBirth; } + public Pet adoptionDate(LocalDateTime adoptionDate) { + this.adoptionDate = adoptionDate; + return this; + } + + /** + * Get adoptionDate + * @return adoptionDate + */ + @Valid + @Schema(name = "adoptionDate", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @JsonProperty("adoptionDate") + public LocalDateTime getAdoptionDate() { + return adoptionDate; + } + + @JsonProperty("adoptionDate") + public void setAdoptionDate(LocalDateTime adoptionDate) { + this.adoptionDate = adoptionDate; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -191,12 +215,13 @@ public boolean equals(Object o) { Objects.equals(this.happy, pet.happy) && Objects.equals(this.price, pet.price) && Objects.equals(this.lastFeed, pet.lastFeed) && - Objects.equals(this.dateOfBirth, pet.dateOfBirth); + Objects.equals(this.dateOfBirth, pet.dateOfBirth) && + Objects.equals(this.adoptionDate, pet.adoptionDate); } @Override public int hashCode() { - return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth); + return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, adoptionDate); } @Override @@ -209,6 +234,7 @@ public String toString() { sb.append(" price: ").append(toIndentedString(price)).append("\n"); sb.append(" lastFeed: ").append(toIndentedString(lastFeed)).append("\n"); sb.append(" dateOfBirth: ").append(toIndentedString(dateOfBirth)).append("\n"); + sb.append(" adoptionDate: ").append(toIndentedString(adoptionDate)).append("\n"); sb.append("}"); return sb.toString(); }