Skip to content

Commit

Permalink
[java][client] Add a "serializationLibrary" option (#3759)
Browse files Browse the repository at this point in the history
* [java][client] Add a "serializationLibrary" option

* Update docs
  • Loading branch information
jmini authored and wing328 committed Aug 28, 2019
1 parent dc7bcbd commit 60e4c92
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 24 deletions.
1 change: 1 addition & 0 deletions docs/generators/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ sidebar_label: java
|useReflectionEqualsHashCode|Use org.apache.commons.lang3.builder for equals and hashCode in the models. WARNING: This will fail under a security manager, unless the appropriate permissions are set up correctly and also there's potential performance impact.| |false|
|caseInsensitiveResponseHeaders|Make API response's headers case-insensitive. Available on okhttp-gson, jersey2 libraries| |false|
|library|library template (sub-template) to use|<dl><dt>**jersey1**</dt><dd>HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.8.x. Enable Java6 support using '-DsupportJava6=true'. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey2' or other HTTP libaries instead.</dd><dt>**jersey2**</dt><dd>HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.8.x</dd><dt>**feign**</dt><dd>HTTP client: OpenFeign 9.x or 10.x. JSON processing: Jackson 2.8.x. To enable OpenFeign 10.x, set the 'feignVersion' option to '10.x'</dd><dt>**okhttp-gson**</dt><dd>[DEFAULT] HTTP client: OkHttp 3.x. JSON processing: Gson 2.8.x. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'.</dd><dt>**retrofit**</dt><dd>HTTP client: OkHttp 2.x. JSON processing: Gson 2.x (Retrofit 1.9.0). IMPORTANT NOTE: retrofit1.x is no longer actively maintained so please upgrade to 'retrofit2' instead.</dd><dt>**retrofit2**</dt><dd>HTTP client: OkHttp 3.x. JSON processing: Gson 2.x (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2]=true'. (RxJava 1.x or 2.x)</dd><dt>**resttemplate**</dt><dd>HTTP client: Spring RestTemplate 4.x. JSON processing: Jackson 2.8.x</dd><dt>**webclient**</dt><dd>HTTP client: Spring WebClient 5.x. JSON processing: Jackson 2.9.x</dd><dt>**resteasy**</dt><dd>HTTP client: Resteasy client 3.x. JSON processing: Jackson 2.8.x</dd><dt>**vertx**</dt><dd>HTTP client: VertX client 3.x. JSON processing: Jackson 2.8.x</dd><dt>**google-api-client**</dt><dd>HTTP client: Google API client 1.x. JSON processing: Jackson 2.8.x</dd><dt>**rest-assured**</dt><dd>HTTP client: rest-assured : 4.x. JSON processing: Gson 2.x. Only for Java8</dd><dt>**native**</dt><dd>HTTP client: Java native HttpClient. JSON processing: Jackson 2.9.x. Only for Java11+</dd><dl>|okhttp-gson|
|serializationLibrary|Serialization library, default depends from the library|<dl><dt>**jackson**</dt><dd>Use Jackson as serialization library</dd><dt>**gson**</dt><dd>Use Gson as serialization library</dd><dl>|null|
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String RETROFIT_2 = "retrofit2";
public static final String VERTX = "vertx";

public static final String SERIALIZATION_LIBRARY = "serializationLibrary";
public static final String SERIALIZATION_LIBRARY_GSON = "gson";
public static final String SERIALIZATION_LIBRARY_JACKSON = "jackson";

protected String gradleWrapperPackage = "gradle.wrapper";
protected boolean useRxJava = false;
protected boolean useRxJava2 = false;
Expand All @@ -95,6 +99,8 @@ public class JavaClientCodegen extends AbstractJavaCodegen
protected boolean useReflectionEqualsHashCode = false;
protected boolean caseInsensitiveResponseHeaders = false;
protected String authFolder;
protected String serializationLibrary = null;


public JavaClientCodegen() {
super();
Expand Down Expand Up @@ -128,7 +134,6 @@ public JavaClientCodegen() {
cliOptions.add(CliOption.newBoolean(USE_REFLECTION_EQUALS_HASHCODE, "Use org.apache.commons.lang3.builder for equals and hashCode in the models. WARNING: This will fail under a security manager, unless the appropriate permissions are set up correctly and also there's potential performance impact."));
cliOptions.add(CliOption.newBoolean(CASE_INSENSITIVE_RESPONSE_HEADERS, "Make API response's headers case-insensitive. Available on " + OKHTTP_GSON + ", " + JERSEY2 + " libraries"));


supportedLibraries.put(JERSEY1, "HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.8.x. Enable Java6 support using '-DsupportJava6=true'. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey2' or other HTTP libaries instead.");
supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.8.x");
supportedLibraries.put(FEIGN, "HTTP client: OpenFeign 9.x or 10.x. JSON processing: Jackson 2.8.x. To enable OpenFeign 10.x, set the 'feignVersion' option to '10.x'");
Expand All @@ -150,6 +155,12 @@ public JavaClientCodegen() {
cliOptions.add(libraryOption);
setLibrary(OKHTTP_GSON);

CliOption serializationLibrary = new CliOption(SERIALIZATION_LIBRARY, "Serialization library, default depends from the library");
Map<String, String> serializationOptions = new HashMap<>();
serializationOptions.put(SERIALIZATION_LIBRARY_GSON, "Use Gson as serialization library");
serializationOptions.put(SERIALIZATION_LIBRARY_JACKSON, "Use Jackson as serialization library");
serializationLibrary.setEnum(serializationOptions);
cliOptions.add(serializationLibrary);
}

@Override
Expand Down Expand Up @@ -284,6 +295,10 @@ public void processOpts() {
"BeanValidationException.java"));
}

if (additionalProperties.containsKey(SERIALIZATION_LIBRARY)) {
setSerializationLibrary(additionalProperties.get(SERIALIZATION_LIBRARY).toString());
}

//TODO: add doc to retrofit1 and feign
if (FEIGN.equals(getLibrary()) || RETROFIT_1.equals(getLibrary())) {
modelDocTemplateFiles.remove("model_doc.mustache");
Expand All @@ -301,7 +316,7 @@ public void processOpts() {
}

if (FEIGN.equals(getLibrary())) {
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java"));
supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java"));
} else if (OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) {
Expand All @@ -316,48 +331,48 @@ public void processOpts() {
// NOTE: below moved to postProcessOpoerationsWithModels
//supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
//supportingFiles.add(new SupportingFile("auth/RetryingOAuth.mustache", authFolder, "RetryingOAuth.java"));
additionalProperties.put("gson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_GSON);
} else if (usesAnyRetrofitLibrary()) {
supportingFiles.add(new SupportingFile("auth/OAuthOkHttpClient.mustache", authFolder, "OAuthOkHttpClient.java"));
supportingFiles.add(new SupportingFile("CollectionFormats.mustache", invokerFolder, "CollectionFormats.java"));
additionalProperties.put("gson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_GSON);
if ("retrofit2".equals(getLibrary()) && !usePlayWS) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
}
} else if (JERSEY2.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (NATIVE.equals(getLibrary())) {
setJava8Mode(true);
additionalProperties.put("java8", "true");
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (RESTEASY.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (JERSEY1.equals(getLibrary())) {
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (RESTTEMPLATE.equals(getLibrary())) {
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
} else if (WEBCLIENT.equals(getLibrary())) {
setJava8Mode(true);
additionalProperties.put("java8", "true");
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (VERTX.equals(getLibrary())) {
typeMapping.put("file", "AsyncFile");
importMapping.put("AsyncFile", "io.vertx.core.file.AsyncFile");
setJava8Mode(true);
additionalProperties.put("java8", "true");
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
apiTemplateFiles.put("apiImpl.mustache", "Impl.java");
apiTemplateFiles.put("rxApiImpl.mustache", ".java");
supportingFiles.remove(new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml"));
} else if (GOOGLE_API_CLIENT.equals(getLibrary())) {
additionalProperties.put("jackson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);

} else if (REST_ASSURED.equals(getLibrary())) {
additionalProperties.put("gson", "true");
forceSerializationLibrary(SERIALIZATION_LIBRARY_GSON);
additionalProperties.put("convert", new CaseFormatLambda(LOWER_CAMEL, UPPER_UNDERSCORE));
apiTemplateFiles.put("api.mustache", ".java");
supportingFiles.add(new SupportingFile("ResponseSpecBuilders.mustache", invokerFolder, "ResponseSpecBuilders.java"));
Expand Down Expand Up @@ -415,16 +430,30 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java"));
supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java"));

additionalProperties.put("jackson", "true");
additionalProperties.remove("gson");
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
}

if (additionalProperties.containsKey("jackson") && !NATIVE.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
if ("threetenbp".equals(dateLibrary) && !usePlayWS) {
supportingFiles.add(new SupportingFile("CustomInstantDeserializer.mustache", invokerFolder, "CustomInstantDeserializer.java"));
if(getSerializationLibrary() == null) {
LOGGER.info("No serializationLibrary configured, using '"+SERIALIZATION_LIBRARY_GSON+"' as fallback");
setSerializationLibrary(SERIALIZATION_LIBRARY_GSON);
}
if(SERIALIZATION_LIBRARY_JACKSON.equals(getSerializationLibrary())) {
additionalProperties.put(SERIALIZATION_LIBRARY_JACKSON, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_GSON);
if (!NATIVE.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", invokerFolder, "RFC3339DateFormat.java"));
if ("threetenbp".equals(dateLibrary) && !usePlayWS) {
supportingFiles.add(new SupportingFile("CustomInstantDeserializer.mustache", invokerFolder, "CustomInstantDeserializer.java"));
}
}
} else if (SERIALIZATION_LIBRARY_GSON.equals(getSerializationLibrary())) {
additionalProperties.put(SERIALIZATION_LIBRARY_GSON, "true");
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
} else {
additionalProperties.remove(SERIALIZATION_LIBRARY_JACKSON);
additionalProperties.remove(SERIALIZATION_LIBRARY_GSON);
}

}

private boolean usesAnyRetrofitLibrary() {
Expand Down Expand Up @@ -581,12 +610,12 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
if (!BooleanUtils.toBoolean(model.isEnum)) {
//final String lib = getLibrary();
//Needed imports for Jackson based libraries
if (additionalProperties.containsKey("jackson")) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
model.imports.add("JsonProperty");
model.imports.add("JsonValue");
model.imports.add("JsonInclude");
}
if (additionalProperties.containsKey("gson")) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_GSON)) {
model.imports.add("SerializedName");
model.imports.add("TypeAdapter");
model.imports.add("JsonAdapter");
Expand All @@ -596,7 +625,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
}
} else { // enum class
//Needed imports for Jackson's JsonCreator
if (additionalProperties.containsKey("jackson")) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
model.imports.add("JsonValue");
model.imports.add("JsonCreator");
}
Expand All @@ -607,7 +636,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
objs = super.postProcessModelsEnum(objs);
//Needed import for Gson based libraries
if (additionalProperties.containsKey("gson")) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_GSON)) {
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Expand All @@ -628,7 +657,7 @@ public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
objs = super.postProcessModels(objs);
if (additionalProperties.containsKey("jackson") && !JERSEY1.equals(getLibrary())) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON) && !JERSEY1.equals(getLibrary())) {
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
List<Object> models = (List<Object>) objs.get("models");
for (Object _mo : models) {
Expand Down Expand Up @@ -712,6 +741,31 @@ public void setCaseInsensitiveResponseHeaders(final Boolean caseInsensitiveRespo
this.caseInsensitiveResponseHeaders = caseInsensitiveResponseHeaders;
}

/**
* Serialization library.
* @return 'gson' or 'jackson'
*/
public String getSerializationLibrary() {
return serializationLibrary;
}

public void setSerializationLibrary(String serializationLibrary) {
if(SERIALIZATION_LIBRARY_JACKSON.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_JACKSON;
} else if(SERIALIZATION_LIBRARY_GSON.equalsIgnoreCase(serializationLibrary)) {
this.serializationLibrary = SERIALIZATION_LIBRARY_GSON;
} else {
throw new IllegalArgumentException("Unexpected serializationLibrary value: " + serializationLibrary);
}
}

public void forceSerializationLibrary(String serializationLibrary) {
if((this.serializationLibrary != null) && !this.serializationLibrary.equalsIgnoreCase(serializationLibrary)) {
LOGGER.warn("The configured serializationLibrary '" + this.serializationLibrary + "', is not supported by the library: '" + getLibrary() + "', switching back to: " + serializationLibrary);
}
setSerializationLibrary(serializationLibrary);
}

final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application\\/json(;.*)?");
final private static Pattern JSON_VENDOR_MIME_PATTERN = Pattern.compile("(?i)application\\/vnd.(.*)+json(;.*)?");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public void testInitialConfigValues() throws Exception {
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "org.openapitools.client.api");
Assert.assertEquals(codegen.getInvokerPackage(), "org.openapitools.client");
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.INVOKER_PACKAGE), "org.openapitools.client");
Assert.assertEquals(codegen.getSerializationLibrary(), JavaClientCodegen.SERIALIZATION_LIBRARY_GSON);
}

@Test
Expand All @@ -159,6 +160,7 @@ public void testSettersForConfigValues() throws Exception {
codegen.setModelPackage("xyz.yyyyy.zzzzzzz.model");
codegen.setApiPackage("xyz.yyyyy.zzzzzzz.api");
codegen.setInvokerPackage("xyz.yyyyy.zzzzzzz.invoker");
codegen.setSerializationLibrary("JACKSON");
codegen.processOpts();

Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.TRUE);
Expand All @@ -169,6 +171,7 @@ public void testSettersForConfigValues() throws Exception {
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xyz.yyyyy.zzzzzzz.api");
Assert.assertEquals(codegen.getInvokerPackage(), "xyz.yyyyy.zzzzzzz.invoker");
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.INVOKER_PACKAGE), "xyz.yyyyy.zzzzzzz.invoker");
Assert.assertEquals(codegen.getSerializationLibrary(), JavaClientCodegen.SERIALIZATION_LIBRARY_GSON); // the library JavaClientCodegen.OKHTTP_GSON only supports GSON
}

@Test
Expand All @@ -178,6 +181,8 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception {
codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xyz.yyyyy.zzzzzzz.mmmmm.model");
codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xyz.yyyyy.zzzzzzz.aaaaa.api");
codegen.additionalProperties().put(CodegenConstants.INVOKER_PACKAGE, "xyz.yyyyy.zzzzzzz.iiii.invoker");
codegen.additionalProperties().put(JavaClientCodegen.SERIALIZATION_LIBRARY, "JACKSON");
codegen.additionalProperties().put(CodegenConstants.LIBRARY, JavaClientCodegen.JERSEY2);
codegen.processOpts();

Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.TRUE);
Expand All @@ -188,6 +193,7 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception {
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "xyz.yyyyy.zzzzzzz.aaaaa.api");
Assert.assertEquals(codegen.getInvokerPackage(), "xyz.yyyyy.zzzzzzz.iiii.invoker");
Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.INVOKER_PACKAGE), "xyz.yyyyy.zzzzzzz.iiii.invoker");
Assert.assertEquals(codegen.getSerializationLibrary(), JavaClientCodegen.SERIALIZATION_LIBRARY_JACKSON);
}

@Test
Expand Down

0 comments on commit 60e4c92

Please sign in to comment.