Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,8 @@ public void processOpts() {
importMapping.put("LocalTime", "java.time.LocalTime");
typeMapping.put("date-time-local", "LocalDateTime");
importMapping.put("LocalDateTime", "java.time.LocalDateTime");
typeMapping.put("duration", "Duration");
importMapping.put("Duration", "java.time.Duration");
if ("java8-localdatetime".equals(dateLibrary)) {
typeMapping.put("DateTime", "LocalDateTime");
} else {
Expand Down Expand Up @@ -1458,6 +1460,13 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
}
}
return null;
} else if (ModelUtils.isDurationSchema(schema)) {
if (schema.getDefault() != null) {
if ("java8".equals(getDateLibrary())) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Duration defaults are dropped for java8-* variants because this branch only accepts exact java8 even though duration is mapped for all java8* libraries.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java, line 1465:

<comment>Duration defaults are dropped for `java8-*` variants because this branch only accepts exact `java8` even though `duration` is mapped for all `java8*` libraries.</comment>

<file context>
@@ -1458,6 +1460,13 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
             return null;
+        } else if (ModelUtils.isDurationSchema(schema)) {
+            if (schema.getDefault() != null) {
+                if ("java8".equals(getDateLibrary())) {
+                    return String.format(Locale.ROOT, "Duration.parse(\"%s\")", schema.getDefault());
+                }
</file context>

return String.format(Locale.ROOT, "Duration.parse(\"%s\")", schema.getDefault());
}
}
return null;
} else if (ModelUtils.isStringSchema(schema)) {
if (schema.getDefault() != null) {
String _default;
Expand Down Expand Up @@ -1548,6 +1557,10 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
if("java8".equals(getDateLibrary())) {
defaultPropertyExpression = String.format(Locale.ROOT, "java.time.LocalDateTime.parse(\"%s\")", value.asText());
}
} else if(ModelUtils.isDurationSchema(propertySchema)) {
if("java8".equals(getDateLibrary())) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Nested duration properties have the same exact-java8 gate, so defaults are also dropped for java8-* variants.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java, line 1561:

<comment>Nested `duration` properties have the same exact-`java8` gate, so defaults are also dropped for `java8-*` variants.</comment>

<file context>
@@ -1548,6 +1557,10 @@ public String toDefaultValue(CodegenProperty cp, Schema schema) {
                                     defaultPropertyExpression = String.format(Locale.ROOT, "java.time.LocalDateTime.parse(\"%s\")", value.asText());
                                 }
+                            } else if(ModelUtils.isDurationSchema(propertySchema)) {
+                                if("java8".equals(getDateLibrary())) {
+                                    defaultPropertyExpression = String.format(Locale.ROOT, "java.time.Duration.parse(\"%s\")", value.asText());
+                                }
</file context>

defaultPropertyExpression = String.format(Locale.ROOT, "java.time.Duration.parse(\"%s\")", value.asText());
}
} else if(ModelUtils.isUUIDSchema(propertySchema)) {
defaultPropertyExpression = "java.util.UUID.fromString(\"" + value.asText() + "\")";
} else if(ModelUtils.isStringSchema(propertySchema)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,12 @@ public static boolean isDateTimeLocalSchema(Schema schema) {
&& "date-time-local".equals(schema.getFormat()));
}

public static boolean isDurationSchema(Schema schema) {
// format: duration, see https://spec.openapis.org/registry/format/duration.html
return (SchemaTypeUtil.STRING_TYPE.equals(getType(schema))
&& "duration".equals(schema.getFormat()));
}

public static boolean isTimeLocalSchema(Schema schema) {
// format: time-local, see https://spec.openapis.org/registry/format/time-local.html
return (SchemaTypeUtil.STRING_TYPE.equals(getType(schema))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,15 @@ public void toDefaultValueDateTimeLegacyTest() {

// dateLibrary <> java8
Assert.assertEquals(defaultValue, "2007-12-03T10:15:30");

// Test default value for duration format
StringSchema durationSchema = new StringSchema();
durationSchema.setFormat("duration");
durationSchema.setDefault(Duration.parse("PT20.345S"));
defaultValue = codegen.toDefaultValue(durationSchema);

// dateLibrary <> java8
Assert.assertEquals(defaultValue, "PT20.345S");
}

@Test
Expand Down Expand Up @@ -622,6 +631,13 @@ public void toDefaultValueTest() {
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 default value for duration format
StringSchema durationSchema = new StringSchema();
durationSchema.setFormat("duration");
durationSchema.setDefault("PT20.345S");
defaultValue = codegen.toDefaultValue(codegen.fromProperty("", durationSchema), durationSchema);
Assert.assertEquals(defaultValue, "Duration.parse(\"PT20.345S\")");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,35 @@ public void generateLocalDateTimeForDateTimeLocalFormat() throws IOException {
.assertProperty("adoptionDate").withType("LocalDateTime");
}

@Test
public void generateDurationForDurationFormat() 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.Duration")
.assertProperty("tripDuration").withType("Duration");
}

@Test
public void interfaceDefaultImplDisableWithResponseWrapper() {
final SpringCodegen codegen = new SpringCodegen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,8 @@ components:
adoptionDate:
type: string
format: date-time-local
default: '2007-12-03T10:15:30'
default: '2007-12-03T10:15:30'
tripDuration:
type: string
format: duration
default: 'PT10H15M30S'
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
Expand Down Expand Up @@ -46,6 +47,8 @@ public class Pet {

private LocalDateTime adoptionDate = LocalDateTime.parse("2007-12-03T10:15:30");

private Duration tripDuration = Duration.parse("PT10H15M30S");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Mapping OpenAPI duration to java.time.Duration rejects valid RFC3339 duration values with year/month/week components, so payloads like P1Y or P2W will not deserialize correctly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/spring-cloud-date-time/src/main/java/org/openapitools/model/Pet.java, line 50:

<comment>Mapping OpenAPI `duration` to `java.time.Duration` rejects valid RFC3339 duration values with year/month/week components, so payloads like `P1Y` or `P2W` will not deserialize correctly.</comment>

<file context>
@@ -46,6 +47,8 @@ public class Pet {
 
   private LocalDateTime adoptionDate = LocalDateTime.parse("2007-12-03T10:15:30");
 
+  private Duration tripDuration = Duration.parse("PT10H15M30S");
+
   public Pet() {
</file context>


public Pet() {
super();
}
Expand Down Expand Up @@ -225,6 +228,27 @@ public void setAdoptionDate(LocalDateTime adoptionDate) {
this.adoptionDate = adoptionDate;
}

public Pet tripDuration(Duration tripDuration) {
this.tripDuration = tripDuration;
return this;
}

/**
* Get tripDuration
* @return tripDuration
*/
@Valid
@Schema(name = "tripDuration", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonProperty("tripDuration")
public Duration getTripDuration() {
return tripDuration;
}

@JsonProperty("tripDuration")
public void setTripDuration(Duration tripDuration) {
this.tripDuration = tripDuration;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -241,12 +265,13 @@ public boolean equals(Object o) {
Objects.equals(this.lastFeed, pet.lastFeed) &&
Objects.equals(this.dateOfBirth, pet.dateOfBirth) &&
Objects.equals(this.feedingTime, pet.feedingTime) &&
Objects.equals(this.adoptionDate, pet.adoptionDate);
Objects.equals(this.adoptionDate, pet.adoptionDate) &&
Objects.equals(this.tripDuration, pet.tripDuration);
}

@Override
public int hashCode() {
return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, feedingTime, adoptionDate);
return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, feedingTime, adoptionDate, tripDuration);
}

@Override
Expand All @@ -261,6 +286,7 @@ public String toString() {
sb.append(" dateOfBirth: ").append(toIndentedString(dateOfBirth)).append("\n");
sb.append(" feedingTime: ").append(toIndentedString(feedingTime)).append("\n");
sb.append(" adoptionDate: ").append(toIndentedString(adoptionDate)).append("\n");
sb.append(" tripDuration: ").append(toIndentedString(tripDuration)).append("\n");
sb.append("}");
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
Expand Down Expand Up @@ -46,6 +47,8 @@ public class Pet {

private LocalDateTime adoptionDate = LocalDateTime.parse("2007-12-03T10:15:30");

private Duration tripDuration = Duration.parse("PT10H15M30S");

public Pet() {
super();
}
Expand Down Expand Up @@ -225,6 +228,27 @@ public void setAdoptionDate(LocalDateTime adoptionDate) {
this.adoptionDate = adoptionDate;
}

public Pet tripDuration(Duration tripDuration) {
this.tripDuration = tripDuration;
return this;
}

/**
* Get tripDuration
* @return tripDuration
*/
@Valid
@Schema(name = "tripDuration", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonProperty("tripDuration")
public Duration getTripDuration() {
return tripDuration;
}

@JsonProperty("tripDuration")
public void setTripDuration(Duration tripDuration) {
this.tripDuration = tripDuration;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand All @@ -241,12 +265,13 @@ public boolean equals(Object o) {
Objects.equals(this.lastFeed, pet.lastFeed) &&
Objects.equals(this.dateOfBirth, pet.dateOfBirth) &&
Objects.equals(this.feedingTime, pet.feedingTime) &&
Objects.equals(this.adoptionDate, pet.adoptionDate);
Objects.equals(this.adoptionDate, pet.adoptionDate) &&
Objects.equals(this.tripDuration, pet.tripDuration);
}

@Override
public int hashCode() {
return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, feedingTime, adoptionDate);
return Objects.hash(atType, age, happy, price, lastFeed, dateOfBirth, feedingTime, adoptionDate, tripDuration);
}

@Override
Expand All @@ -261,6 +286,7 @@ public String toString() {
sb.append(" dateOfBirth: ").append(toIndentedString(dateOfBirth)).append("\n");
sb.append(" feedingTime: ").append(toIndentedString(feedingTime)).append("\n");
sb.append(" adoptionDate: ").append(toIndentedString(adoptionDate)).append("\n");
sb.append(" tripDuration: ").append(toIndentedString(tripDuration)).append("\n");
sb.append("}");
return sb.toString();
}
Expand Down
Loading