Skip to content

Commit b4b70b1

Browse files
martin-mfgbeikov
authored andcommitted
[OpenAPITools#19921] Add RFC 3339 compatible Jackson module for java.time types, regenerate samples (OpenAPITools#20700)
Co-authored-by: Christian Beikov <christian.beikov@gmail.com>
1 parent 9aba5b3 commit b4b70b1

File tree

176 files changed

+6657
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+6657
-5
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,8 @@ public void processOpts() {
726726
additionalProperties.remove(SERIALIZATION_LIBRARY_GSON);
727727
additionalProperties.remove(SERIALIZATION_LIBRARY_JSONB);
728728
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
729+
supportingFiles.add(new SupportingFile("RFC3339InstantDeserializer.mustache", invokerFolder, "RFC3339InstantDeserializer.java"));
730+
supportingFiles.add(new SupportingFile("RFC3339JavaTimeModule.mustache", invokerFolder, "RFC3339JavaTimeModule.java"));
729731
break;
730732
case SERIALIZATION_LIBRARY_GSON:
731733
additionalProperties.put(SERIALIZATION_LIBRARY_GSON, "true");
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{{>licenseInfo}}
2+
package {{invokerPackage}};
3+
4+
import java.io.IOException;
5+
import java.time.Instant;
6+
import java.time.OffsetDateTime;
7+
import java.time.ZoneId;
8+
import java.time.ZonedDateTime;
9+
import java.time.format.DateTimeFormatter;
10+
import java.time.temporal.Temporal;
11+
import java.time.temporal.TemporalAccessor;
12+
import java.util.function.BiFunction;
13+
import java.util.function.Function;
14+
15+
import com.fasterxml.jackson.core.JsonParser;
16+
import com.fasterxml.jackson.databind.DeserializationContext;
17+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature;
18+
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
19+
20+
{{>generatedAnnotation}}
21+
public class RFC3339InstantDeserializer<T extends Temporal> extends InstantDeserializer<T> {
22+
23+
private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID.enabledByDefault();
24+
private final static boolean DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
25+
= JavaTimeFeature.ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS.enabledByDefault();
26+
27+
public static final RFC3339InstantDeserializer<Instant> INSTANT = new RFC3339InstantDeserializer<>(
28+
Instant.class, DateTimeFormatter.ISO_INSTANT,
29+
Instant::from,
30+
a -> Instant.ofEpochMilli( a.value ),
31+
a -> Instant.ofEpochSecond( a.integer, a.fraction ),
32+
null,
33+
true, // yes, replace zero offset with Z
34+
DEFAULT_NORMALIZE_ZONE_ID,
35+
DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
36+
);
37+
38+
public static final RFC3339InstantDeserializer<OffsetDateTime> OFFSET_DATE_TIME = new RFC3339InstantDeserializer<>(
39+
OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME,
40+
OffsetDateTime::from,
41+
a -> OffsetDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ),
42+
a -> OffsetDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ),
43+
(d, z) -> ( d.isEqual( OffsetDateTime.MIN ) || d.isEqual( OffsetDateTime.MAX ) ?
44+
d :
45+
d.withOffsetSameInstant( z.getRules().getOffset( d.toLocalDateTime() ) ) ),
46+
true, // yes, replace zero offset with Z
47+
DEFAULT_NORMALIZE_ZONE_ID,
48+
DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
49+
);
50+
51+
public static final RFC3339InstantDeserializer<ZonedDateTime> ZONED_DATE_TIME = new RFC3339InstantDeserializer<>(
52+
ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME,
53+
ZonedDateTime::from,
54+
a -> ZonedDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ),
55+
a -> ZonedDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ),
56+
ZonedDateTime::withZoneSameInstant,
57+
false, // keep zero offset and Z separate since zones explicitly supported
58+
DEFAULT_NORMALIZE_ZONE_ID,
59+
DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
60+
);
61+
62+
protected RFC3339InstantDeserializer(
63+
Class<T> supportedType,
64+
DateTimeFormatter formatter,
65+
Function<TemporalAccessor, T> parsedToValue,
66+
Function<FromIntegerArguments, T> fromMilliseconds,
67+
Function<FromDecimalArguments, T> fromNanoseconds,
68+
BiFunction<T, ZoneId, T> adjust,
69+
boolean replaceZeroOffsetAsZ,
70+
boolean normalizeZoneId,
71+
boolean readNumericStringsAsTimestamp) {
72+
super(
73+
supportedType,
74+
formatter,
75+
parsedToValue,
76+
fromMilliseconds,
77+
fromNanoseconds,
78+
adjust,
79+
replaceZeroOffsetAsZ,
80+
normalizeZoneId,
81+
readNumericStringsAsTimestamp
82+
);
83+
}
84+
85+
@Override
86+
protected T _fromString(JsonParser p, DeserializationContext ctxt, String string0) throws IOException {
87+
return super._fromString(p, ctxt, string0.replace( ' ', 'T' ));
88+
}
89+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{>licenseInfo}}
2+
package {{invokerPackage}};
3+
4+
import java.time.Instant;
5+
import java.time.OffsetDateTime;
6+
import java.time.ZonedDateTime;
7+
8+
import com.fasterxml.jackson.databind.module.SimpleModule;
9+
10+
{{>generatedAnnotation}}
11+
public class RFC3339JavaTimeModule extends SimpleModule {
12+
13+
public RFC3339JavaTimeModule() {
14+
super("RFC3339JavaTimeModule");
15+
16+
addDeserializer(Instant.class, RFC3339InstantDeserializer.INSTANT);
17+
addDeserializer(OffsetDateTime.class, RFC3339InstantDeserializer.OFFSET_DATE_TIME);
18+
addDeserializer(ZonedDateTime.class, RFC3339InstantDeserializer.ZONED_DATE_TIME);
19+
}
20+
}

modules/openapi-generator/src/main/resources/Java/libraries/apache-httpclient/ApiClient.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {
149149
{{#openApiNullable}}
150150
objectMapper.registerModule(new JsonNullableModule());
151151
{{/openApiNullable}}
152+
objectMapper.registerModule(new RFC3339JavaTimeModule());
152153
objectMapper.setDateFormat(ApiClient.buildDefaultDateFormat());
153154

154155
dateFormat = ApiClient.buildDefaultDateFormat();

modules/openapi-generator/src/main/resources/Java/libraries/feign/ApiClient.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public class ApiClient {
186186
objectMapper.registerModule(new JodaModule());
187187
{{/joda}}
188188
objectMapper.registerModule(new JavaTimeModule());
189+
objectMapper.registerModule(new RFC3339JavaTimeModule());
189190
{{#openApiNullable}}
190191
JsonNullableModule jnm = new JsonNullableModule();
191192
objectMapper.registerModule(jnm);

modules/openapi-generator/src/main/resources/Java/libraries/jersey2/JSON.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class JSON implements ContextResolver<ObjectMapper> {
4242
{{#openApiNullable}}
4343
.addModule(new JsonNullableModule())
4444
{{/openApiNullable}}
45+
.addModule(new RFC3339JavaTimeModule())
4546
.build();
4647
}
4748

modules/openapi-generator/src/main/resources/Java/libraries/jersey3/JSON.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class JSON implements ContextResolver<ObjectMapper> {
4242
{{#openApiNullable}}
4343
.addModule(new JsonNullableModule())
4444
{{/openApiNullable}}
45+
.addModule(new RFC3339JavaTimeModule())
4546
.build();
4647
}
4748

modules/openapi-generator/src/main/resources/Java/libraries/native/ApiClient.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ public class ApiClient {
196196
{{#openApiNullable}}
197197
mapper.registerModule(new JsonNullableModule());
198198
{{/openApiNullable}}
199+
mapper.registerModule(new RFC3339JavaTimeModule());
199200
return mapper;
200201
}
201202

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ public void testJdkHttpClient() {
537537

538538
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
539539

540-
assertThat(files).hasSize(32);
540+
assertThat(files).hasSize(34);
541541
validateJavaSourceFiles(files);
542542
assertThat(output.resolve("src/main/java/xyz/abcdef/api/DefaultApi.java")).content().contains(
543543
"public class DefaultApi",
@@ -607,7 +607,7 @@ public void testJdkHttpAsyncClient() {
607607

608608
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
609609

610-
assertThat(files).hasSize(35);
610+
assertThat(files).hasSize(37);
611611

612612
validateJavaSourceFiles(files);
613613
assertThat(output.resolve("src/main/java/xyz/abcdef/api/PingApi.java")).content().contains(
@@ -1428,7 +1428,7 @@ public void testNativeClientWhiteSpacePathParamEncoding() {
14281428
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
14291429

14301430
validateJavaSourceFiles(files);
1431-
assertThat(files).hasSize(35);
1431+
assertThat(files).hasSize(37);
14321432
TestUtils.assertFileContains(output.resolve("src/main/java/xyz/abcdef/ApiClient.java"),
14331433
"public static String urlEncode(String s) { return URLEncoder.encode(s,"
14341434
+ " UTF_8).replaceAll(\"\\\\+\", \"%20\"); }"
@@ -1451,7 +1451,7 @@ public void testNativeClientExplodedQueryParamObject() {
14511451
List<File> files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
14521452

14531453
validateJavaSourceFiles(files);
1454-
assertThat(files).hasSize(38);
1454+
assertThat(files).hasSize(40);
14551455
assertThat(output.resolve("src/main/java/xyz/abcdef/api/DefaultApi.java")).content()
14561456
.contains(
14571457
"localVarQueryParams.addAll(ApiClient.parameterToPairs(\"since\", queryObject.getSince()));",

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/apachehttpclient/ApacheHttpClientCodegenTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public void testApacheHttpClientExplodedQueryParamObject() throws IOException {
5656
DefaultGenerator generator = new DefaultGenerator();
5757
List<File> files = generator.opts(clientOptInput).generate();
5858

59-
Assert.assertEquals(files.size(), 42);
59+
Assert.assertEquals(files.size(), 44);
6060
validateJavaSourceFiles(files);
6161

6262
TestUtils.assertFileContains(Paths.get(output + "/src/main/java/xyz/abcdef/api/DefaultApi.java"),

0 commit comments

Comments
 (0)