Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jersey2-experimental to Java client generator #6024

Merged
merged 21 commits into from
Apr 24, 2020
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
4 changes: 4 additions & 0 deletions bin/java-petstore-jersey2-experimental.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"library": "jersey2-experimental",
"artifactId": "petstore-jersey2-exp"
}
48 changes: 48 additions & 0 deletions bin/java-petstore-jersey2-experimental.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh

SCRIPT="$0"
echo "# START SCRIPT: $SCRIPT"

while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi

executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"

if [ ! -f "$executable" ]
then
mvn -B clean package
fi

# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -g java -c bin/java-petstore-jersey2-experimental.json -o samples/client/petstore/java/jersey2-experimental -t modules/openapi-generator/src/main/resources/Java --additional-properties hideGenerationTimestamp=true $@"

echo "Removing files and folders under samples/client/petstore/java/jersey2-experimental/src/main"
rm -rf samples/client/petstore/java/jersey2-experimental/src/main
find samples/client/petstore/java/jersey2-experimental -maxdepth 1 -type f ! -name "README.md" -exec rm {} +
java $JAVA_OPTS -jar $executable $ags

# copy additional manually written unit-tests
#mkdir samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client
#mkdir samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/auth
#mkdir samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/model

#cp CI/samples.ci/client/petstore/java/test-manual/common/StringUtilTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/StringUtilTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/jersey2/ApiClientTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/ApiClientTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/common/ConfigurationTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/ConfigurationTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/jersey2/auth/ApiKeyAuthTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/auth/ApiKeyAuthTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/jersey2/auth/HttpBasicAuthTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/auth/HttpBasicAuthTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/jersey2/model/EnumValueTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/model/EnumValueTest.java
#cp CI/samples.ci/client/petstore/java/test-manual/jersey2/JSONTest.java samples/client/petstore/java/jersey2/src/test/java/org/openapitools/client/JSONTest.java
2 changes: 1 addition & 1 deletion docs/generators/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ sidebar_label: java
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false|
|invokerPackage|root package for generated code| |org.openapitools.client|
|java8|Option. Use Java8 classes instead of third party equivalents|<dl><dt>**true**</dt><dd>Use Java 8 classes such as Base64</dd><dt>**false**</dt><dd>Various third party libraries as needed</dd></dl>|false|
|library|library template (sub-template) to use|<dl><dt>**jersey1**</dt><dd>HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.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.9.x</dd><dt>**feign**</dt><dd>HTTP client: OpenFeign 9.x (deprecated) or 10.x (default). JSON processing: Jackson 2.9.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.9.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.9.x</dd><dt>**vertx**</dt><dd>HTTP client: VertX client 3.x. JSON processing: Jackson 2.9.x</dd><dt>**google-api-client**</dt><dd>HTTP client: Google API client 1.x. JSON processing: Jackson 2.9.x</dd><dt>**rest-assured**</dt><dd>HTTP client: rest-assured : 4.x. JSON processing: Gson 2.x or Jackson 2.10.x. Only for Java 8</dd><dt>**native**</dt><dd>HTTP client: Java native HttpClient. JSON processing: Jackson 2.9.x. Only for Java11+</dd><dt>**microprofile**</dt><dd>HTTP client: Microprofile client X.x. JSON processing: Jackson 2.9.x</dd></dl>|okhttp-gson|
|library|library template (sub-template) to use|<dl><dt>**jersey1**</dt><dd>HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.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.9.x</dd><dt>**jersey2-experimental**</dt><dd>HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x</dd><dt>**feign**</dt><dd>HTTP client: OpenFeign 9.x (deprecated) or 10.x (default). JSON processing: Jackson 2.9.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.9.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.9.x</dd><dt>**vertx**</dt><dd>HTTP client: VertX client 3.x. JSON processing: Jackson 2.9.x</dd><dt>**google-api-client**</dt><dd>HTTP client: Google API client 1.x. JSON processing: Jackson 2.9.x</dd><dt>**rest-assured**</dt><dd>HTTP client: rest-assured : 4.x. JSON processing: Gson 2.x or Jackson 2.10.x. Only for Java 8</dd><dt>**native**</dt><dd>HTTP client: Java native HttpClient. JSON processing: Jackson 2.9.x. Only for Java11+</dd><dt>**microprofile**</dt><dd>HTTP client: Microprofile client X.x. JSON processing: Jackson 2.9.x</dd></dl>|okhttp-gson|
|licenseName|The name of the license| |Unlicense|
|licenseUrl|The URL of the license| |http://unlicense.org|
|modelPackage|package for generated models| |org.openapitools.client.model|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1846,8 +1846,8 @@ public String toAnyOfName(List<String> names, ComposedSchema composedSchema) {
@SuppressWarnings("static-method")
public String toOneOfName(List<String> names, ComposedSchema composedSchema) {
Map<String, Object> exts = composedSchema.getExtensions();
if (exts != null && exts.containsKey("x-oneOf-name")) {
return (String) exts.get("x-oneOf-name");
if (exts != null && exts.containsKey("x-one-of-name")) {
return (String) exts.get("x-one-of-name");
}
return "oneOf<" + String.join(",", names) + ">";
}
Expand Down Expand Up @@ -2186,9 +2186,33 @@ public CodegenModel fromModel(String name, Schema schema) {
m.interfaces = new ArrayList<String>();

for (Schema interfaceSchema : interfaces) {
interfaceSchema = ModelUtils.unaliasSchema(this.openAPI, interfaceSchema, importMapping);

if (StringUtils.isBlank(interfaceSchema.get$ref())) {
// primitive type
String languageType = getTypeDeclaration(interfaceSchema);

if (composed.getAnyOf() != null) {
if (m.anyOf.contains(languageType)) {
LOGGER.warn("{} (anyOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
} else {
m.anyOf.add(languageType);
}
} else if (composed.getOneOf() != null) {
if (m.oneOf.contains(languageType)) {
LOGGER.warn("{} (oneOf schema) already has `{}` defined and therefore it's skipped.", m.name, languageType);
} else {
m.oneOf.add(languageType);
}
} else if (composed.getAllOf() != null) {
// no need to add primitive type to allOf, which should comprise of schemas (models) only
} else {
LOGGER.error("Composed schema has incorrect anyOf, allOf, oneOf defined: {}", composed);
}
continue;
}

// the rest of the section is for model
Schema refSchema = null;
String ref = ModelUtils.getSimpleRef(interfaceSchema.get$ref());
if (allDefinitions != null) {
Expand Down Expand Up @@ -2389,8 +2413,10 @@ protected void addProperties(Map<String, Schema> properties, List<String> requir
if (schema instanceof ComposedSchema) {
ComposedSchema composedSchema = (ComposedSchema) schema;

for (Schema component : composedSchema.getAllOf()) {
addProperties(properties, required, component);
if (composedSchema.getAllOf() != null) {
for (Schema component : composedSchema.getAllOf()) {
addProperties(properties, required, component);
}
}

if (schema.getRequired() != null) {
Expand Down Expand Up @@ -5767,14 +5793,14 @@ public void setRemoveEnumValuePrefix(final boolean removeEnumValuePrefix) {
//// Following methods are related to the "useOneOfInterfaces" feature

/**
* Add "x-oneOf-name" extension to a given oneOf schema (assuming it has at least 1 oneOf elements)
* Add "x-one-of-name" extension to a given oneOf schema (assuming it has at least 1 oneOf elements)
*
* @param s schema to add the extension to
* @param name name of the parent oneOf schema
*/
public void addOneOfNameExtension(ComposedSchema s, String name) {
if (s.getOneOf() != null && s.getOneOf().size() > 0) {
s.addExtension("x-oneOf-name", name);
s.addExtension("x-one-of-name", name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public static final String GOOGLE_API_CLIENT = "google-api-client";
public static final String JERSEY1 = "jersey1";
public static final String JERSEY2 = "jersey2";
public static final String JERSEY2_EXPERIMENTAL = "jersey2-experimental";
public static final String NATIVE = "native";
public static final String OKHTTP_GSON = "okhttp-gson";
public static final String RESTEASY = "resteasy";
Expand Down Expand Up @@ -144,6 +145,7 @@ public JavaClientCodegen() {

supportedLibraries.put(JERSEY1, "HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.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.9.x");
supportedLibraries.put(JERSEY2_EXPERIMENTAL, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x");
supportedLibraries.put(FEIGN, "HTTP client: OpenFeign 9.x (deprecated) or 10.x (default). JSON processing: Jackson 2.9.x.");
supportedLibraries.put(OKHTTP_GSON, "[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'.");
supportedLibraries.put(RETROFIT_1, "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.");
Expand Down Expand Up @@ -367,9 +369,12 @@ public void processOpts() {
if ("retrofit2".equals(getLibrary()) && !usePlayWS) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
}
} else if (JERSEY2.equals(getLibrary())) {
} else if (JERSEY2.equals(getLibrary()) || JERSEY2_EXPERIMENTAL.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java"));
supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java"));
if (JERSEY2_EXPERIMENTAL.equals(getLibrary())) {
supportingFiles.add(new SupportingFile("AbstractOpenApiSchema.mustache", (sourceFolder + File.separator + modelPackage().replace('.', File.separatorChar)).replace('/', File.separatorChar), "AbstractOpenApiSchema.java"));
}
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
} else if (NATIVE.equals(getLibrary())) {
setJava8Mode(true);
Expand Down Expand Up @@ -499,7 +504,7 @@ public void processOpts() {
additionalProperties.remove(SERIALIZATION_LIBRARY_GSON);
}

if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON)) {
if (additionalProperties.containsKey(SERIALIZATION_LIBRARY_JACKSON) && !JERSEY2_EXPERIMENTAL.equals(getLibrary())) {
useOneOfInterfaces = true;
addOneOfInterfaceImports = true;
}
Expand Down Expand Up @@ -595,6 +600,39 @@ public int compare(CodegenParameter one, CodegenParameter another) {
objs = AbstractJavaJAXRSServerCodegen.jaxrsPostProcessOperations(objs);
}

if (JERSEY2_EXPERIMENTAL.equals(getLibrary())) {
// index the model
HashMap<String, CodegenModel> modelMaps = new HashMap<String, CodegenModel>();
for (Object o : allModels) {
HashMap<String, Object> h = (HashMap<String, Object>) o;
CodegenModel m = (CodegenModel) h.get("model");
modelMaps.put(m.classname, m);

}

// check if return type is oneOf/anyeOf model
Map<String, Object> operations = (Map<String, Object>) objs.get("operations");
List<CodegenOperation> operationList = (List<CodegenOperation>) operations.get("operation");
for (CodegenOperation op : operationList) {
if (op.returnType != null) {
// look up the model to see if it's anyOf/oneOf
if (modelMaps.containsKey(op.returnType) && modelMaps.get(op.returnType) != null) {
CodegenModel cm = modelMaps.get(op.returnType);

if (cm.oneOf != null && !cm.oneOf.isEmpty()) {
op.vendorExtensions.put("x-java-return-type-one-of", true);
}

if (cm.anyOf != null && !cm.anyOf.isEmpty()) {
op.vendorExtensions.put("x-java-return-type-any-of", true);
}
} else {
//LOGGER.error("cannot lookup model " + op.returnType);
}
}
}
}

return objs;
}

Expand Down Expand Up @@ -769,12 +807,16 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
CodegenModel cm = (CodegenModel) mo.get("model");
cm.getVendorExtensions().putIfAbsent("implements", new ArrayList<String>()); // TODO: 5.0 Remove
cm.getVendorExtensions().putIfAbsent("x-implements", cm.getVendorExtensions().get("implements"));
List<String> impl = (List<String>) cm.getVendorExtensions().get("implements");
//List<String> impl = (List<String>) cm.getVendorExtensions().get("x-implements");
if (JERSEY2_EXPERIMENTAL.equals(getLibrary())) {
cm.getVendorExtensions().put("x-implements", new ArrayList<String>());
}

if (this.parcelableModel) {
impl.add("Parcelable");
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Parcelable");
}
if (this.serializableModel) {
impl.add("Serializable");
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Serializable");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,45 @@ import {{invokerPackage}}.ApiException;
{{/imports}}
import org.junit.Test;
import org.junit.Ignore;
import org.junit.Assert;

{{^fullJavaUtil}}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}

{{/fullJavaUtil}}
/**
* API tests for {{classname}}
*/
@Ignore
public class {{classname}}Test {

private final {{classname}} api = new {{classname}}();

{{#operations}}{{#operation}}
{{#operations}}
{{#operation}}
/**
{{#summary}}
* {{summary}}
*
{{/summary}}
{{#notes}}
* {{notes}}
*
{{/notes}}
* @throws ApiException
* if the Api call fails
*/
@Test
public void {{operationId}}Test() throws ApiException {
{{#allParams}}
{{{dataType}}} {{paramName}} = null;
{{/allParams}}
{{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
//{{#allParams}}
//{{{dataType}}} {{paramName}} = null;
//{{/allParams}}
//{{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});

// TODO: test validations
}
{{/operation}}{{/operations}}
{{/operation}}
{{/operations}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{{>licenseInfo}}

package {{invokerPackage}}.model;

import org.openapitools.client.ApiException;
import java.lang.reflect.Type;
import java.util.Map;
import javax.ws.rs.core.GenericType;

{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}
public abstract class AbstractOpenApiSchema {

private Object instance;

public final String schemaType;

public AbstractOpenApiSchema(String schemaType) {
this.schemaType = schemaType;
}

public abstract Map<String, GenericType> getSchemas();

public Object getActualInstance() {return instance;}

public void setActualInstance(Object instance) {this.instance = instance;}

public String getSchemaType() {
return schemaType;
}
}
Loading