Skip to content
Merged
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
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