Skip to content

Commit 2a9e1e6

Browse files
add jackson 3 support to java native
1 parent 8515f5e commit 2a9e1e6

16 files changed

Lines changed: 277 additions & 8 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
generatorName: java
2+
outputDir: samples/client/petstore/java/native-jackson3
3+
library: native
4+
inputSpec: modules/openapi-generator/src/test/resources/3_0/java/native/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml
5+
templateDir: modules/openapi-generator/src/main/resources/Java
6+
additionalProperties:
7+
artifactId: petstore-native-jackson3
8+
hideGenerationTimestamp: "true"
9+
generateBuilders: true
10+
useReflectionEqualsHashCode: "true"
11+
useJackson3: "true"

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
107107
public static final String SUPPORT_VERTX_FUTURE = "supportVertxFuture";
108108
public static final String USE_SEALED_ONE_OF_INTERFACES = "useSealedOneOfInterfaces";
109109
public static final String USE_UNARY_INTERCEPTOR = "useUnaryInterceptor";
110+
public static final String USE_JACKSON_3 = "useJackson3";
110111

111112
// Internal configurations
112113
public static final String SINGLE_REQUEST_PARAMETER = "singleRequestParameter";
@@ -152,6 +153,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
152153
@Setter protected boolean supportVertxFuture = false;
153154
@Setter protected boolean useSealedOneOfInterfaces = false;
154155
@Setter protected boolean useUnaryInterceptor = false;
156+
@Getter @Setter protected boolean useJackson3 = false;
155157

156158
protected String authFolder;
157159
/**
@@ -262,6 +264,7 @@ public JavaClientCodegen() {
262264
cliOptions.add(CliOption.newBoolean(SUPPORT_URL_QUERY, "Generate toUrlQueryString in POJO (default to true). Available on `native`, `apache-httpclient` libraries."));
263265
cliOptions.add(CliOption.newBoolean(USE_ENUM_CASE_INSENSITIVE, "Use `equalsIgnoreCase` when String for enum comparison", useEnumCaseInsensitive));
264266
cliOptions.add(CliOption.newBoolean(FAIL_ON_UNKNOWN_PROPERTIES, "Fail Jackson de-serialization on unknown properties", this.failOnUnknownProperties));
267+
cliOptions.add(CliOption.newBoolean(USE_JACKSON_3, "Use Jackson 3 instead of Jackson 2 for JSON processing. Only supported for 'native' library.", this.useJackson3));
265268
cliOptions.add(CliOption.newBoolean(SUPPORT_VERTX_FUTURE, "Also generate api methods that return a vertx Future instead of taking a callback. Only `vertx` supports this option. Requires vertx 4 or greater.", this.supportVertxFuture));
266269
cliOptions.add(CliOption.newBoolean(USE_SEALED_ONE_OF_INTERFACES, "Generate the oneOf interfaces as sealed interfaces. Only supported for WebClient and RestClient.", this.useSealedOneOfInterfaces));
267270
cliOptions.add(CliOption.newBoolean(USE_UNARY_INTERCEPTOR, "If true it will generate ResponseInterceptors using a UnaryOperator. This can be usefull for manipulating the request before it gets passed, for example doing your own decryption", this.useUnaryInterceptor));
@@ -454,6 +457,7 @@ public void processOpts() {
454457
convertPropertyToBooleanAndWriteBack(WEBCLIENT_BLOCKING_OPERATIONS, op -> webclientBlockingOperations = op);
455458
convertPropertyToBooleanAndWriteBack(FAIL_ON_UNKNOWN_PROPERTIES, this::setFailOnUnknownProperties);
456459
convertPropertyToBooleanAndWriteBack(SUPPORT_VERTX_FUTURE, this::setSupportVertxFuture);
460+
convertPropertyToBooleanAndWriteBack(USE_JACKSON_3, this::setUseJackson3);
457461

458462
// add URL query deepObject support to native, apache-httpclient by default
459463
if (!additionalProperties.containsKey(SUPPORT_URL_QUERY)) {
@@ -810,6 +814,33 @@ public void processOpts() {
810814
break;
811815
}
812816

817+
// Jackson 3 support: update importMapping to use tools.jackson.* packages
818+
if (useJackson3) {
819+
if (!libNative) {
820+
LOGGER.warn("useJackson3 option is currently only supported for library=native. Ignoring useJackson3.");
821+
useJackson3 = false;
822+
additionalProperties.put(USE_JACKSON_3, false);
823+
} else {
824+
importMapping.put("JsonProperty", "tools.jackson.annotation.JsonProperty");
825+
importMapping.put("JsonSubTypes", "tools.jackson.annotation.JsonSubTypes");
826+
importMapping.put("JsonTypeInfo", "tools.jackson.annotation.JsonTypeInfo");
827+
importMapping.put("JsonTypeName", "tools.jackson.annotation.JsonTypeName");
828+
importMapping.put("JsonCreator", "tools.jackson.annotation.JsonCreator");
829+
importMapping.put("JsonValue", "tools.jackson.annotation.JsonValue");
830+
importMapping.put("JsonIgnore", "tools.jackson.annotation.JsonIgnore");
831+
importMapping.put("JsonIgnoreProperties", "tools.jackson.annotation.JsonIgnoreProperties");
832+
importMapping.put("JsonInclude", "tools.jackson.annotation.JsonInclude");
833+
importMapping.put("JsonDeserialize", "tools.jackson.databind.annotation.JsonDeserialize");
834+
importMapping.put("JsonFormat", "tools.jackson.annotation.JsonFormat");
835+
// Secondary rule: when JsonProperty is imported, also import JsonCreator (Jackson 3)
836+
importMapping.put("tools.jackson.annotation.JsonProperty", "tools.jackson.annotation.JsonCreator");
837+
if (openApiNullable) {
838+
LOGGER.warn("openApiNullable with useJackson3=true: JsonNullableModule is not yet available for Jackson 3. " +
839+
"JsonNullable types will be generated but module registration will be skipped.");
840+
}
841+
}
842+
}
843+
813844
if (isLibrary(FEIGN)) {
814845
additionalProperties.put("feign-okhttp", "true");
815846
} else if (isLibrary(FEIGN_HC5)) {

modules/openapi-generator/src/main/resources/Java/RFC3339DateFormat.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
{{>licenseInfo}}
22
package {{invokerPackage}};
33

4+
{{^useJackson3}}
45
import com.fasterxml.jackson.databind.util.StdDateFormat;
6+
{{/useJackson3}}
7+
{{#useJackson3}}
8+
import tools.jackson.databind.util.StdDateFormat;
9+
{{/useJackson3}}
510

611
import java.text.DateFormat;
712
import java.text.FieldPosition;

modules/openapi-generator/src/main/resources/Java/RFC3339InstantDeserializer.mustache

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
{{>licenseInfo}}
22
package {{invokerPackage}};
33

4+
{{^useJackson3}}
45
import java.io.IOException;
6+
{{/useJackson3}}
57
import java.time.Instant;
68
import java.time.OffsetDateTime;
79
import java.time.ZoneId;
@@ -12,10 +14,19 @@ import java.time.temporal.TemporalAccessor;
1214
import java.util.function.BiFunction;
1315
import java.util.function.Function;
1416

17+
{{^useJackson3}}
1518
import com.fasterxml.jackson.core.JsonParser;
1619
import com.fasterxml.jackson.databind.DeserializationContext;
1720
import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature;
1821
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
22+
{{/useJackson3}}
23+
{{#useJackson3}}
24+
import tools.jackson.core.JacksonException;
25+
import tools.jackson.core.JsonParser;
26+
import tools.jackson.databind.DeserializationContext;
27+
import tools.jackson.datatype.jsr310.JavaTimeFeature;
28+
import tools.jackson.datatype.jsr310.deser.InstantDeserializer;
29+
{{/useJackson3}}
1930

2031
{{>generatedAnnotation}}
2132

@@ -84,7 +95,7 @@ public class RFC3339InstantDeserializer<T extends Temporal> extends InstantDeser
8495
}
8596

8697
@Override
87-
protected T _fromString(JsonParser p, DeserializationContext ctxt, String string0) throws IOException {
98+
protected T _fromString(JsonParser p, DeserializationContext ctxt, String string0) throws {{^useJackson3}}IOException{{/useJackson3}}{{#useJackson3}}JacksonException{{/useJackson3}} {
8899
return super._fromString(p, ctxt, string0.replace( ' ', 'T' ));
89100
}
90101
}

modules/openapi-generator/src/main/resources/Java/RFC3339JavaTimeModule.mustache

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import java.time.Instant;
55
import java.time.OffsetDateTime;
66
import java.time.ZonedDateTime;
77

8+
{{^useJackson3}}
89
import com.fasterxml.jackson.databind.module.SimpleModule;
910
import com.fasterxml.jackson.databind.Module.SetupContext;
11+
{{/useJackson3}}
12+
{{#useJackson3}}
13+
import tools.jackson.databind.module.SimpleModule;
14+
{{/useJackson3}}
1015

1116
{{>generatedAnnotation}}
1217

@@ -15,8 +20,14 @@ public class RFC3339JavaTimeModule extends SimpleModule {
1520
1621
public RFC3339JavaTimeModule() {
1722
super("RFC3339JavaTimeModule");
23+
{{#useJackson3}}
24+
addDeserializer(Instant.class, RFC3339InstantDeserializer.INSTANT);
25+
addDeserializer(OffsetDateTime.class, RFC3339InstantDeserializer.OFFSET_DATE_TIME);
26+
addDeserializer(ZonedDateTime.class, RFC3339InstantDeserializer.ZONED_DATE_TIME);
27+
{{/useJackson3}}
1828
}
1929

30+
{{^useJackson3}}
2031
@Override
2132
public void setupModule(SetupContext context) {
2233
super.setupModule(context);
@@ -25,5 +36,6 @@ public class RFC3339JavaTimeModule extends SimpleModule {
2536
addDeserializer(OffsetDateTime.class, RFC3339InstantDeserializer.OFFSET_DATE_TIME);
2637
addDeserializer(ZonedDateTime.class, RFC3339InstantDeserializer.ZONED_DATE_TIME);
2738
}
39+
{{/useJackson3}}
2840

2941
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import java.util.Objects;
66
import java.lang.reflect.Type;
77
import java.util.Map;
88

9+
{{^useJackson3}}
910
import com.fasterxml.jackson.annotation.JsonValue;
11+
{{/useJackson3}}
12+
{{#useJackson3}}
13+
import tools.jackson.annotation.JsonValue;
14+
{{/useJackson3}}
1015

1116
/**
1217
* Abstract class for oneOf,anyOf schemas defined in OpenAPI spec

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{{>licenseInfo}}
22
package {{invokerPackage}};
33

4+
{{^useJackson3}}
45
import com.fasterxml.jackson.annotation.JsonInclude;
56
import com.fasterxml.jackson.databind.DeserializationFeature;
67
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -9,6 +10,14 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
910
{{#openApiNullable}}
1011
import org.openapitools.jackson.nullable.JsonNullableModule;
1112
{{/openApiNullable}}
13+
{{/useJackson3}}
14+
{{#useJackson3}}
15+
import tools.jackson.annotation.JsonInclude;
16+
import tools.jackson.databind.DeserializationFeature;
17+
import tools.jackson.databind.ObjectMapper;
18+
import tools.jackson.databind.SerializationFeature;
19+
import tools.jackson.datatype.jsr310.JavaTimeModule;
20+
{{/useJackson3}}
1221

1322
import java.io.InputStream;
1423
import java.io.IOException;
@@ -214,9 +223,14 @@ public class ApiClient {
214223
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
215224
mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
216225
mapper.registerModule(new JavaTimeModule());
226+
{{^useJackson3}}
217227
{{#openApiNullable}}
218228
mapper.registerModule(new JsonNullableModule());
219229
{{/openApiNullable}}
230+
{{/useJackson3}}
231+
{{#useJackson3}}
232+
// FIXME: JsonNullableModule is not yet available for Jackson 3
233+
{{/useJackson3}}
220234
mapper.registerModule(new RFC3339JavaTimeModule());
221235
return mapper;
222236
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
package {{invokerPackage}};
44

5+
{{^useJackson3}}
56
import com.fasterxml.jackson.annotation.*;
67
import com.fasterxml.jackson.databind.*;
78
import com.fasterxml.jackson.databind.json.JsonMapper;
@@ -12,6 +13,16 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
1213
{{#joda}}
1314
import com.fasterxml.jackson.datatype.joda.JodaModule;
1415
{{/joda}}
16+
{{/useJackson3}}
17+
{{#useJackson3}}
18+
import tools.jackson.annotation.*;
19+
import tools.jackson.databind.*;
20+
import tools.jackson.databind.json.JsonMapper;
21+
import tools.jackson.datatype.jsr310.JavaTimeModule;
22+
{{#joda}}
23+
import tools.jackson.datatype.joda.JodaModule;
24+
{{/joda}}
25+
{{/useJackson3}}
1526
{{#models.0}}
1627
import {{modelPackage}}.*;
1728
{{/models.0}}
@@ -28,6 +39,7 @@ public class JSON {
2839
private ObjectMapper mapper;
2940
3041
public JSON() {
42+
{{^useJackson3}}
3143
mapper = JsonMapper.builder()
3244
.serializationInclusion(JsonInclude.Include.NON_NULL)
3345
.disable(MapperFeature.ALLOW_COERCION_OF_SCALARS)
@@ -51,6 +63,29 @@ public class JSON {
5163
JsonNullableModule jnm = new JsonNullableModule();
5264
mapper.registerModule(jnm);
5365
{{/openApiNullable}}
66+
{{/useJackson3}}
67+
{{#useJackson3}}
68+
mapper = JsonMapper.builder()
69+
.serializationInclusion(JsonInclude.Include.NON_NULL)
70+
// Note: MapperFeature.ALLOW_COERCION_OF_SCALARS was removed in Jackson 3
71+
{{#failOnUnknownProperties}}
72+
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
73+
{{/failOnUnknownProperties}}
74+
{{^failOnUnknownProperties}}
75+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
76+
{{/failOnUnknownProperties}}
77+
.enable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)
78+
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
79+
.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
80+
.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
81+
.defaultDateFormat(new RFC3339DateFormat())
82+
.addModule(new JavaTimeModule())
83+
.build();
84+
{{#joda}}
85+
mapper.registerModule(new JodaModule());
86+
{{/joda}}
87+
// FIXME: JsonNullableModule is not yet available for Jackson 3
88+
{{/useJackson3}}
5489
}
5590

5691
/**

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
{{^useJackson3}}
12
import java.io.IOException;
3+
{{/useJackson3}}
24
import java.util.logging.Level;
35
import java.util.logging.Logger;
46
import java.util.ArrayList;
57
import java.util.Collections;
68
import java.util.HashSet;
79

10+
{{^useJackson3}}
811
import com.fasterxml.jackson.core.JsonGenerator;
912
import com.fasterxml.jackson.core.JsonParser;
1013
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -16,6 +19,20 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
1619
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
1720
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
1821
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
22+
{{/useJackson3}}
23+
{{#useJackson3}}
24+
import tools.jackson.core.JacksonException;
25+
import tools.jackson.core.JsonGenerator;
26+
import tools.jackson.core.JsonParser;
27+
import tools.jackson.databind.DeserializationContext;
28+
import tools.jackson.databind.JsonMappingException;
29+
import tools.jackson.databind.JsonNode;
30+
import tools.jackson.databind.SerializerProvider;
31+
import tools.jackson.databind.annotation.JsonDeserialize;
32+
import tools.jackson.databind.annotation.JsonSerialize;
33+
import tools.jackson.databind.deser.std.StdDeserializer;
34+
import tools.jackson.databind.ser.std.StdSerializer;
35+
{{/useJackson3}}
1936
import {{invokerPackage}}.ApiClient;
2037
import {{invokerPackage}}.JSON;
2138

@@ -35,7 +52,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
3552
}
3653

3754
@Override
38-
public void serialize({{classname}} value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
55+
public void serialize({{classname}} value, JsonGenerator jgen, SerializerProvider provider) throws {{^useJackson3}}IOException, JsonProcessingException{{/useJackson3}}{{#useJackson3}}JacksonException{{/useJackson3}} {
3956
jgen.writeObject(value.getActualInstance());
4057
}
4158
}
@@ -50,7 +67,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
5067
}
5168

5269
@Override
53-
public {{classname}} deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
70+
public {{classname}} deserialize(JsonParser jp, DeserializationContext ctxt) throws {{^useJackson3}}IOException, JsonProcessingException{{/useJackson3}}{{#useJackson3}}JacksonException{{/useJackson3}} {
5471
JsonNode tree = jp.readValueAsTree();
5572
5673
Object deserialized = null;
@@ -79,7 +96,8 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
7996
}
8097

8198
{{/anyOf}}
82-
throw new IOException("Failed deserialization for {{classname}}: no match found");
99+
{{^useJackson3}}throw new IOException("Failed deserialization for {{classname}}: no match found");{{/useJackson3}}
100+
{{#useJackson3}}throw new JsonMappingException(jp, "Failed deserialization for {{classname}}: no match found");{{/useJackson3}}
83101
}
84102

85103
/**

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ import {{invokerPackage}}.Pair;
1111
import {{import}};
1212
{{/imports}}
1313

14+
{{^useJackson3}}
1415
import com.fasterxml.jackson.core.type.TypeReference;
1516
import com.fasterxml.jackson.databind.ObjectMapper;
17+
{{/useJackson3}}
18+
{{#useJackson3}}
19+
import tools.jackson.core.type.TypeReference;
20+
import tools.jackson.databind.ObjectMapper;
21+
{{/useJackson3}}
1622

1723
{{#useBeanValidation}}
1824
import {{javaxPackage}}.validation.constraints.*;

0 commit comments

Comments
 (0)