-
Notifications
You must be signed in to change notification settings - Fork 6k
[Java] Templates to support google-api-client library #6838
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
Changes from all commits
c65e75b
4e1ac5d
482b21a
8445a59
43ed38b
bc1d4ea
bc86f90
76a157f
023fd4c
0c9d862
a118b0e
88ee6fc
db0e2b7
ecd6d21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "library": "google-api-client", | ||
| "artifactId": "swagger-petstore-google-api-client" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #!/bin/sh | ||
|
|
||
| SCRIPT="$0" | ||
|
|
||
| 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/swagger-codegen-cli/target/swagger-codegen-cli.jar" | ||
|
|
||
| if [ ! -f "$executable" ] | ||
| then | ||
| mvn clean package | ||
| fi | ||
|
|
||
| # if you've executed sbt assembly previously it will use that instead. | ||
| export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties" | ||
| ags="$@ generate -t modules/swagger-codegen/src/main/resources/Java/libraries/google-api-client -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l java -c bin/java-petstore-google-api-client.json -o samples/client/petstore/java/google-api-client -DhideGenerationTimestamp=true" | ||
|
|
||
| echo "Removing files and folders under samples/client/petstore/java/google-api-client/src/main" | ||
| rm -rf samples/client/petstore/java/google-api-client/src/main | ||
| find samples/client/petstore/java/google-api-client -maxdepth 1 -type f ! -name "README.md" -exec rm {} + | ||
| java $JAVA_OPTS -jar $executable $ags |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,6 +82,7 @@ public JavaClientCodegen() { | |
| supportedLibraries.put("resttemplate", "HTTP client: Spring RestTemplate 4.3.9-RELEASE. JSON processing: Jackson 2.8.9"); | ||
| supportedLibraries.put("resteasy", "HTTP client: Resteasy client 3.1.3.Final. JSON processing: Jackson 2.8.9"); | ||
| supportedLibraries.put("vertx", "HTTP client: VertX client 3.2.4. JSON processing: Jackson 2.8.9"); | ||
| supportedLibraries.put("google-api-client", "HTTP client: Google API client 1.23.0. JSON processing: Jackson 2.8.9"); | ||
|
|
||
| CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); | ||
| libraryOption.setEnum(supportedLibraries); | ||
|
|
@@ -172,10 +173,13 @@ public void processOpts() { | |
| supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java")); | ||
| } | ||
|
|
||
| supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); | ||
| // google-api-client doesn't use the Swagger auth, because it uses Google Credential directly (HttpRequestInitializer) | ||
| if (!"google-api-client".equals(getLibrary())) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should go in the GoogleApiClientCodegen.java since it's only useful for your generator.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I'll do that right now, sounds like a plan.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI this is following the existing pattern. There actually aren't any subclasses of |
||
| supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); | ||
| supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); | ||
| } | ||
| supportingFiles.add(new SupportingFile( "gradlew.mustache", "", "gradlew") ); | ||
| supportingFiles.add(new SupportingFile( "gradlew.bat.mustache", "", "gradlew.bat") ); | ||
| supportingFiles.add(new SupportingFile( "gradle-wrapper.properties.mustache", | ||
|
|
@@ -196,7 +200,7 @@ public void processOpts() { | |
| apiDocTemplateFiles.remove("api_doc.mustache"); | ||
| } | ||
|
|
||
| if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary())) { | ||
| if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary() || "google-api-client".equals(getLibrary()))) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I see other library has done it too... @wing328, is this normal? Since we are using objects, we should'nt have any "if" in the JavaClientCodegen... It should all be in specific file of each generator...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it appears there are no subclasses of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. It's weird because for example, for the server generator "java play framework" which I maintain, there is: Same thing for Typescript jQuery which I maintain too: I wonder why the JavaClientCodegen are all mixed in one file.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. Yeah, a refactor into subclasses probably belongs in a separate pull request, but I'm game to do whatever you suggest.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is ok for now and belong in another pull request like you said. :)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we added support for other HTTP libraries, we didn't foresee we can support so many libraries (9 HTTP libraries support so far thanks to the awesome community). I agree a separate PR to refactor into subclasses would be ideal.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. Is this waiting on any additional reviews? Let me know if any more changes are needed here. Thanks! This will really help out our company in our migration to use Swagger clients for all of our service-to-service communication. (And possibly we could use this for our Android app, too).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @charlescapps I'll take another look later today and merge accordingly. |
||
| supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java")); | ||
| supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java")); | ||
| supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java")); | ||
|
|
@@ -240,6 +244,8 @@ public void processOpts() { | |
| 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"); | ||
| } else { | ||
| LOGGER.error("Unknown library option (-l/--library): " + getLibrary()); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| package {{invokerPackage}}; | ||
|
|
||
| import {{apiPackage}}.*; | ||
| import com.fasterxml.jackson.databind.DeserializationFeature; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.fasterxml.jackson.databind.SerializationFeature; | ||
| {{#joda}} | ||
| import com.fasterxml.jackson.datatype.joda.JodaModule; | ||
| {{/joda}} | ||
| {{#java8}} | ||
| import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | ||
| {{/java8}} | ||
| {{#threetenbp}} | ||
| import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; | ||
| {{/threetenbp}} | ||
| {{#threetenbp}} | ||
| import org.threeten.bp.*; | ||
| {{/threetenbp}} | ||
| import com.google.api.client.googleapis.util.Utils; | ||
| import com.google.api.client.http.AbstractHttpContent; | ||
| import com.google.api.client.http.HttpRequestFactory; | ||
| import com.google.api.client.http.HttpRequestInitializer; | ||
| import com.google.api.client.http.HttpTransport; | ||
| import com.google.api.client.json.Json; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.OutputStream; | ||
|
|
||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| {{>generatedAnnotation}} | ||
| public class ApiClient { | ||
| private final String basePath; | ||
| private final HttpRequestFactory httpRequestFactory; | ||
| private final ObjectMapper objectMapper; | ||
|
|
||
| private static final String defaultBasePath = "{{basePath}}"; | ||
|
|
||
| // A reasonable default object mapper. Client can pass in a chosen ObjectMapper anyway, this is just for reasonable defaults. | ||
| private static ObjectMapper createDefaultObjectMapper() { | ||
| ObjectMapper objectMapper = new ObjectMapper() | ||
| .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) | ||
| .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) | ||
| .setDateFormat(new RFC3339DateFormat()); | ||
| {{#joda}} | ||
| objectMapper.registerModule(new JodaModule()); | ||
| {{/joda}} | ||
| {{#java8}} | ||
| objectMapper.registerModule(new JavaTimeModule()); | ||
| {{/java8}} | ||
| {{#threetenbp}} | ||
| ThreeTenModule module = new ThreeTenModule(); | ||
| module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); | ||
| module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); | ||
| module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); | ||
| objectMapper.registerModule(module); | ||
| {{/threetenbp}} | ||
| return objectMapper; | ||
| } | ||
|
|
||
| public ApiClient() { | ||
| this(null, null, null, null); | ||
| } | ||
|
|
||
| public ApiClient( | ||
| String basePath, | ||
| HttpTransport httpTransport, | ||
| HttpRequestInitializer initializer, | ||
| ObjectMapper objectMapper | ||
| ) { | ||
| this.basePath = basePath == null ? defaultBasePath : ( | ||
| basePath.endsWith("/") ? basePath.substring(0, basePath.length() - 1) : basePath | ||
| ); | ||
| this.httpRequestFactory = (httpTransport == null ? Utils.getDefaultTransport() : httpTransport).createRequestFactory(initializer); | ||
| this.objectMapper = (objectMapper == null ? createDefaultObjectMapper() : objectMapper); | ||
| } | ||
|
|
||
| public HttpRequestFactory getHttpRequestFactory() { | ||
| return httpRequestFactory; | ||
| } | ||
|
|
||
| public String getBasePath() { | ||
| return basePath; | ||
| } | ||
|
|
||
| public ObjectMapper getObjectMapper() { | ||
| return objectMapper; | ||
| } | ||
|
|
||
| public class JacksonJsonHttpContent extends AbstractHttpContent { | ||
| /* A POJO that can be serialized with a com.fasterxml Jackson ObjectMapper */ | ||
| private final Object data; | ||
|
|
||
| public JacksonJsonHttpContent(Object data) { | ||
| super(Json.MEDIA_TYPE); | ||
| this.data = data; | ||
| } | ||
|
|
||
| @Override | ||
| public void writeTo(OutputStream out) throws IOException { | ||
| objectMapper.writeValue(out, data); | ||
| } | ||
| } | ||
|
|
||
| // Builder pattern to get API instances for this client. | ||
| {{#apiInfo}}{{#apis}} | ||
| public {{classname}} {{classVarName}}Api() { | ||
| return new {{classname}}(this); | ||
| } | ||
| {{/apis}}{{/apiInfo}} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised this is needed. Most generator use the params array and loop with "isRequired" to build almost everything. Is there any specific reason to add this to the "generic code"?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you can check
{{isRequired}}but that's not sufficient, because we use{{hasNext}}to see if there's a subsequent element, and that isn't aware ofisRequired, so it was generating code with 2 commas in a row.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok makes sense!