diff --git a/.gitignore b/.gitignore
index e9b1bbce..3cb06f73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ Thumbs.db
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
.gradle
build/
+out/
#NDK
obj/
diff --git a/.travis.yml b/.travis.yml
index c0cf170b..a6f5916f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,12 @@
+dist: bionic
language: java
jdk:
- - openjdk7
+ - openjdk8
+before_install:
+ - sudo apt-get -y install python2.7 python-pip
+ - python2 -m pip install --user google-apis-client-generator
install:
- - JAVA_HOME=$(jdk_switcher home openjdk8) ./gradlew classes testClasses
+ - ./gradlew classes testClasses
after_success:
- ./gradlew jacocoTestReport
- bash <(curl -s https://codecov.io/bash)
diff --git a/README.md b/README.md
index 79b5d969..07678ee6 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,18 @@
-[](https://travis-ci.org/cloudendpoints/endpoints-java)
-[](https://codecov.io/gh/cloudendpoints/endpoints-java)
+[](https://travis-ci.org/AODocs/endpoints-java)
+[](https://codecov.io/gh/AODocs/endpoints-java)
# Endpoints Java Framework
The Endpoints Java Framework aims to be a simple solution to assist in creation
of RESTful web APIs in Java. This repository provides several artifacts, all
-in the `com.google.endpoints` group:
+in the `com.aodocs.endpoints` group:
1. `endpoints-framework`: The core framework, required for all applications
building Endpoints apps.
-2. `endpoints-framework-guice`: An extension for configuring Endpoints using
+2. `endpoints-framework-all`: Same as above, but with repackaged dependencies.
+3. `endpoints-framework-guice`: An extension for configuring Endpoints using
Guice.
-3. `endpoints-framework-tools`: Tools for generating discovery documents,
+4. `endpoints-framework-tools`: Tools for generating discovery documents,
Swagger documents, and client libraries.
The main documents for consuming Endpoints can be found at
@@ -22,54 +23,39 @@ https://cloud.google.com/endpoints/docs/frameworks/java
To install test versions to Maven for easier dependency management, simply run:
gradle install
+
+## Additions to the original project
+
+These are the most notable additions to
+[the original project by Google](https://github.com/cloudendpoints/endpoints-java), currently
+inactive:
+- Runtime
+ - Allow [adding arbitrary data](https://github.com/AODocs/endpoints-java/pull/20) to generic errors
+ - [Improve returned errors](https://github.com/AODocs/endpoints-java/pull/30) on malformed JSON
+ - Validate request parameters/body through [Java bean validation](https://beanvalidation.org/) provided by [Hibernate validator](https://hibernate.org/validator/)
+ - Validate request content-type (must be enable through enableContentTypeValidation servlet parameter)
+- Discovery and Swagger
+ - [Add description on resources and resource usage as request body](https://github.com/AODocs/endpoints-java/commit/bbb1eff2bb9e7d28fc2ec17599257d0ef610531d)
+ - [Support declaring resource properties as required](https://github.com/AODocs/endpoints-java/pull/41)
+ - Support pattern, minimum/maximum attributes
+- Swagger
+ - Generated spec is [fully compatible](https://github.com/AODocs/endpoints-java/pull/34) with
+[Cloud Endpoints Portal](https://cloud.google.com/endpoints/docs/frameworks/dev-portal-overview) (and is 100% valid Swagger spec)
+ - Support [multi-API service](https://github.com/AODocs/endpoints-java/pull/40/commits/1f18d2f64f1538e63a7836a5cd52ff639fc624fd) in Endpoints Management
+ - [New options](https://github.com/AODocs/endpoints-java/pull/37) to combine common parameters in same path, extract parameter refs at spec level, add error model description, customize spec title and description
+ - [Add description support](https://github.com/AODocs/endpoints-java/pull/40/commits/bbb1eff2bb9e7d28fc2ec17599257d0ef610531d) for resource and resource usage
+ - [Configurable naming templates](https://github.com/AODocs/endpoints-java/pull/42) for operationIds and tag names with better defaults
+ - Support exclusiveMinimum/exclusiveMaximum, minLength/maxLength and minItems/maxItems attributes
+
+Check
+[closed PRs](https://github.com/AODocs/endpoints-java/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aclosed)
+for all additions.
+
+## Troubleshooting
+
+* When using validation with java bean validation annotations : in order to have well named parameters instead of _arg0/arg1_ in error messages, your code must be compiled with the `-parameters` options.
-## Migrating from the legacy Endpoints framework
-
-This release replaces the old `appengine-endpoints` artifact. You should replace
-the dependency with the `endpoints-framework` artifact from the
-`com.google.endpoints` group. In Maven, the new dependency looks like this:
-
-
- com.google.endpoints
- endpoints-framework
- 2.0.14
-
-
-In Gradle, the new dependency looks like this:
-
- compile group: 'com.google.endpoints', name: 'endpoints-framework', version: '2.0.14'
-
-You also need to update your `web.xml`. Simply replace all instances of
-`SystemServiceServlet` with `EndpointsServlet` and replace `/_ah/spi/*` with
-`/_ah/api/*`. The new Endpoints configuration should look something like this:
-
-
- EndpointsServlet
- com.google.api.server.spi.EndpointsServlet
-
- services
- com.example.Endpoint1,com.example.Endpoint2
-
-
- restricted
- false
-
-
-
- EndpointsServlet
- /_ah/api/*
-
-
-## Repackaging dependencies
-
-The new version of the Endpoints framework does not repackage its dependencies
-to hide them. If you run into dependency conflicts and need to do so, we
-recommend using the Maven Shade plugin or Gradle Shadow plugin. Full
-instructions on doing so are on the [wiki][1].
## Contributing
-Your contributions are welcome. Please follow the [contributor
-guidelines](/CONTRIBUTING.md).
-
-[1]: https://github.com/cloudendpoints/endpoints-java/wiki/Vendoring-dependencies
+Your contributions are welcome. Please follow the [contributor guidelines](/CONTRIBUTING.md).
diff --git a/build.gradle b/build.gradle
index 4c285e58..a35c9cd8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,6 +35,10 @@ subprojects {
sourceCompatibility = project.sourceCompatibility
targetCompatibility = project.targetCompatibility
options.encoding = 'UTF-8'
+ //required for com.google.api.server.spi.ObjectMapperUtilTest
+ //this need to be configured manually for the module in IntelliJ at:
+ //File | Settings | Build, Execution, Deployment | Compiler | Java Compiler
+ options.compilerArgs << '-parameters'
}
test {
@@ -45,7 +49,7 @@ subprojects {
jacocoTestReport {
reports {
- xml.enabled true
+ xml.required = true
}
}
}
@@ -55,70 +59,64 @@ def configureMaven(project, projectName, projectDescription) {
def ossrhUsername = project.findProperty('ossrhUsername')
def ossrhPassword = project.findProperty('ossrhPassword')
configure(project) {
- apply plugin: 'maven'
+ apply plugin: 'java-library'
+ apply plugin: 'maven-publish'
apply plugin: 'signing'
- task sourceJar(type: Jar, dependsOn: classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
+ java {
+ withJavadocJar()
+ withSourcesJar()
}
- task javadocJar(type: Jar) {
- classifier = 'javadoc'
- from javadoc
- }
-
- artifacts {
- archives sourceJar, javadocJar
- }
-
- signing {
- required { gradle.taskGraph.hasTask('uploadArchives') }
- sign configurations.archives
- }
-
- uploadArchives {
+ publishing {
repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
+ maven {
+ def releasesRepoUrl = "https://aodocs.jfrog.io/artifactory/aodocs-java-release/"
+ def snapshotsRepoUrl = "https://aodocs.jfrog.io/artifactory/aodocs-java-snapshot/"
+ url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
+ credentials {
+ username = ossrhUsername
+ password = ossrhPassword
}
-
- snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
- }
-
- pom.project {
- name projectName
- description projectDescription
- packaging 'jar'
- url 'https://cloud.google.com/endpoints/docs/frameworks/java'
+ }
+ }
+ publications {
+ mavenJava(MavenPublication) {
+ from components.java
+ pom {
+ name = projectName
+ description = projectDescription
+ packaging = 'jar'
+ url = 'https://cloud.google.com/endpoints/docs/frameworks/java'
scm {
- connection 'scm:git:https://github.com/cloudendpoints/endpoints-java'
- developerConnection 'scm:git:https://github.com/cloudendpoints/endpoints-java'
- url 'scm:git:https://github.com/cloudendpoints/endpoints-java'
+ connection = 'scm:git:https://github.com/AODocs/endpoints-java.git'
+ developerConnection = 'scm:git:https://github.com/AODocs/endpoints-java.git'
+ url = 'scm:git:https://github.com/AODocs/endpoints-java.git'
}
licenses {
license {
- name 'The Apache License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ name = 'The Apache License, Version 2.0'
+ url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
- id 'tangd'
- name 'Daniel Tang'
- email 'tangd@google.com'
+ id = 'tangd'
+ name = 'Daniel Tang'
+ email = 'tangd@google.com'
}
}
}
}
}
}
+
+ signing {
+ required { gradle.taskGraph.hasTask('publish') }
+ sign publishing.publications.mavenJava
+ }
}
}
diff --git a/discovery-client/build.gradle b/discovery-client/build.gradle
index 194bacce..0e372587 100644
--- a/discovery-client/build.gradle
+++ b/discovery-client/build.gradle
@@ -14,25 +14,25 @@
* limitations under the License.
*/
apply plugin: 'java'
-apply plugin: 'maven'
+apply plugin: 'maven-publish'
group = 'com.google.apis'
archivesBaseName = 'google-api-services-discovery'
-version = 'v1-rev20151119-1.20.0'
+//the sources are included in the main artifact, the version does not matter
+version = 'doesnotmatter'
-sourceCompatibility = 1.6
-targetCompatibility = 1.6
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
jar.manifest.attributes("Built-By": "Google")
-jar.manifest.attributes("Build-Jdk": "1.6.x")
+jar.manifest.attributes("Build-Jdk": "1.8.x")
-task sourceJar(type: Jar) {
- classifier = 'sources'
- from sourceSets.main.allJava
+java {
+ withSourcesJar()
}
artifacts {
- archives sourceJar
+ archives sourcesJar
}
repositories {
@@ -40,11 +40,11 @@ repositories {
}
dependencies {
- compile module(group: 'com.google.api-client', name: 'google-api-client', version: '1.21.0') {
- module(group: 'com.google.http-client', name: 'google-http-client-jackson2', version: '1.21.0') {
- dependency('com.fasterxml.jackson.core:jackson-core:2.6.4')
- dependency('com.google.http-client:google-http-client:1.21.0')
+ implementation module(group: 'com.google.api-client', name: 'google-api-client', version: "1.32.1") {
+ module(group: 'com.google.http-client', name: 'google-http-client-jackson2', version: "1.40.0") {
+ dependency("com.fasterxml.jackson.core:jackson-core:2.12.5")
+ dependency("com.google.http-client:google-http-client:1.40.0")
}
- dependency('com.google.oauth-client:google-oauth-client:1.21.0')
+ dependency("com.google.oauth-client:google-oauth-client:1.32.1")
}
}
diff --git a/discovery-client/src/main/java/com/google/api/services/discovery/Discovery.java b/discovery-client/src/main/java/com/google/api/services/discovery/Discovery.java
index 1a4e8d19..fca627d4 100644
--- a/discovery-client/src/main/java/com/google/api/services/discovery/Discovery.java
+++ b/discovery-client/src/main/java/com/google/api/services/discovery/Discovery.java
@@ -295,85 +295,7 @@ public GenerateRest set(String parameterName, Object value) {
return (GenerateRest) super.set(parameterName, value);
}
}
- /**
- * Generates the Discovery Document of an API given its configuration.
- *
- * Create a request for the method "apis.generateRpc".
- *
- * This request holds the parameters needed by the discovery server. After setting any optional
- * parameters, call the {@link GenerateRpc#execute()} method to invoke the remote operation.
- *
- * @param content the {@link com.google.api.services.discovery.model.ApiConfig}
- * @return the request
- */
- public GenerateRpc generateRpc(com.google.api.services.discovery.model.ApiConfig content) throws java.io.IOException {
- GenerateRpc result = new GenerateRpc(content);
- initialize(result);
- return result;
- }
-
- public class GenerateRpc extends DiscoveryRequest {
-
- private static final String REST_PATH = "apis/generate/rpc";
-
- /**
- * Generates the Discovery Document of an API given its configuration.
- *
- * Create a request for the method "apis.generateRpc".
- *
- * This request holds the parameters needed by the the discovery server. After setting any
- * optional parameters, call the {@link GenerateRpc#execute()} method to invoke the remote
- * operation.
{@link
- * GenerateRpc#initialize(com.google.api.client.googleapis.services.AbstractGoogleClientRequest)}
- * must be called to initialize this instance immediately after invoking the constructor.
- *
- * @param content the {@link com.google.api.services.discovery.model.ApiConfig}
- * @since 1.13
- */
- protected GenerateRpc(com.google.api.services.discovery.model.ApiConfig content) {
- super(Discovery.this, "POST", REST_PATH, content, com.google.api.services.discovery.model.RpcDescription.class);
- }
-
- @Override
- public GenerateRpc setAlt(java.lang.String alt) {
- return (GenerateRpc) super.setAlt(alt);
- }
-
- @Override
- public GenerateRpc setFields(java.lang.String fields) {
- return (GenerateRpc) super.setFields(fields);
- }
-
- @Override
- public GenerateRpc setKey(java.lang.String key) {
- return (GenerateRpc) super.setKey(key);
- }
-
- @Override
- public GenerateRpc setOauthToken(java.lang.String oauthToken) {
- return (GenerateRpc) super.setOauthToken(oauthToken);
- }
-
- @Override
- public GenerateRpc setPrettyPrint(java.lang.Boolean prettyPrint) {
- return (GenerateRpc) super.setPrettyPrint(prettyPrint);
- }
-
- @Override
- public GenerateRpc setQuotaUser(java.lang.String quotaUser) {
- return (GenerateRpc) super.setQuotaUser(quotaUser);
- }
-
- @Override
- public GenerateRpc setUserIp(java.lang.String userIp) {
- return (GenerateRpc) super.setUserIp(userIp);
- }
-
- @Override
- public GenerateRpc set(String parameterName, Object value) {
- return (GenerateRpc) super.set(parameterName, value);
- }
- }
+
/**
* Retrieve the description of a particular version of an api.
*
@@ -499,131 +421,7 @@ public GetRest set(String parameterName, Object value) {
return (GetRest) super.set(parameterName, value);
}
}
- /**
- * Retrieve the description of a particular version of an api.
- *
- * Create a request for the method "apis.getRpc".
- *
- * This request holds the parameters needed by the discovery server. After setting any optional
- * parameters, call the {@link GetRpc#execute()} method to invoke the remote operation.
- *
- * @param api The name of the API.
- * @param version The version of the API.
- * @return the request
- */
- public GetRpc getRpc(java.lang.String api, java.lang.String version) throws java.io.IOException {
- GetRpc result = new GetRpc(api, version);
- initialize(result);
- return result;
- }
-
- public class GetRpc extends DiscoveryRequest {
-
- private static final String REST_PATH = "apis/{api}/{version}/rpc";
-
- /**
- * Retrieve the description of a particular version of an api.
- *
- * Create a request for the method "apis.getRpc".
- *
- * This request holds the parameters needed by the the discovery server. After setting any
- * optional parameters, call the {@link GetRpc#execute()} method to invoke the remote operation.
- *
{@link
- * GetRpc#initialize(com.google.api.client.googleapis.services.AbstractGoogleClientRequest)} must
- * be called to initialize this instance immediately after invoking the constructor.
- *
- * @param api The name of the API.
- * @param version The version of the API.
- * @since 1.13
- */
- protected GetRpc(java.lang.String api, java.lang.String version) {
- super(Discovery.this, "GET", REST_PATH, null, com.google.api.services.discovery.model.RpcDescription.class);
- this.api = com.google.api.client.util.Preconditions.checkNotNull(api, "Required parameter api must be specified.");
- this.version = com.google.api.client.util.Preconditions.checkNotNull(version, "Required parameter version must be specified.");
- }
-
- @Override
- public com.google.api.client.http.HttpResponse executeUsingHead() throws java.io.IOException {
- return super.executeUsingHead();
- }
-
- @Override
- public com.google.api.client.http.HttpRequest buildHttpRequestUsingHead() throws java.io.IOException {
- return super.buildHttpRequestUsingHead();
- }
-
- @Override
- public GetRpc setAlt(java.lang.String alt) {
- return (GetRpc) super.setAlt(alt);
- }
-
- @Override
- public GetRpc setFields(java.lang.String fields) {
- return (GetRpc) super.setFields(fields);
- }
-
- @Override
- public GetRpc setKey(java.lang.String key) {
- return (GetRpc) super.setKey(key);
- }
-
- @Override
- public GetRpc setOauthToken(java.lang.String oauthToken) {
- return (GetRpc) super.setOauthToken(oauthToken);
- }
-
- @Override
- public GetRpc setPrettyPrint(java.lang.Boolean prettyPrint) {
- return (GetRpc) super.setPrettyPrint(prettyPrint);
- }
-
- @Override
- public GetRpc setQuotaUser(java.lang.String quotaUser) {
- return (GetRpc) super.setQuotaUser(quotaUser);
- }
-
- @Override
- public GetRpc setUserIp(java.lang.String userIp) {
- return (GetRpc) super.setUserIp(userIp);
- }
-
- /** The name of the API. */
- @com.google.api.client.util.Key
- private java.lang.String api;
-
- /** The name of the API.
- */
- public java.lang.String getApi() {
- return api;
- }
-
- /** The name of the API. */
- public GetRpc setApi(java.lang.String api) {
- this.api = api;
- return this;
- }
-
- /** The version of the API. */
- @com.google.api.client.util.Key
- private java.lang.String version;
-
- /** The version of the API.
- */
- public java.lang.String getVersion() {
- return version;
- }
-
- /** The version of the API. */
- public GetRpc setVersion(java.lang.String version) {
- this.version = version;
- return this;
- }
-
- @Override
- public GetRpc set(String parameterName, Object value) {
- return (GetRpc) super.set(parameterName, value);
- }
- }
+
/**
* Retrieve the list of APIs supported at this endpoint.
*
diff --git a/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcDescription.java b/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcDescription.java
deleted file mode 100644
index 74765187..00000000
--- a/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcDescription.java
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-/*
- * This code was generated by https://code.google.com/p/google-apis-client-generator/
- * (build: 2015-11-16 19:10:01 UTC)
- * on 2015-11-19 at 17:34:48 UTC
- * Modify at your own risk.
- */
-
-package com.google.api.services.discovery.model;
-
-/**
- * Model definition for RpcDescription.
- *
- *
This is the Java data model class that specifies how to parse/serialize into the JSON that is
- * transmitted over HTTP when working with the APIs Discovery Service. For a detailed explanation
- * see:
- * http://code.google.com/p/google-http-java-client/wiki/JSON
- *
- *
- * @author Google, Inc.
- */
-@SuppressWarnings("javadoc")
-public final class RpcDescription extends com.google.api.client.json.GenericJson {
-
- /**
- * Authentication information.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private Auth auth;
-
- /**
- * Indicates how the API name should be capitalized and split into various parts. Useful for
- * generating pretty class names.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String canonicalName;
-
- /**
- * The description of the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String description;
-
- /**
- * Indicate the version of the Discovery API used to generate this doc.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String discoveryVersion;
-
- /**
- * A link to human readable documentation for the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String documentationLink;
-
- /**
- * The ETag for this response.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String etag;
-
- /**
- * Enable exponential backoff for suitable methods in the generated clients.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean exponentialBackoffDefault;
-
- /**
- * A list of supported features for this API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.List features;
-
- /**
- * Links to 16x16 and 32x32 icons representing the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private Icons icons;
-
- /**
- * The ID of this API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String id;
-
- /**
- * The kind for this response.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String kind;
-
- /**
- * Labels for the status of this API, such as labs or deprecated.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.List labels;
-
- /**
- * API-level methods for this API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.Map methods;
-
- /**
- * The name of this API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String name;
-
- /**
- * The domain of the owner of the API. Together with the ownerName and a packagePath values, this
- * can be used to generate a library for the API which would have a unique fully qualified name.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String ownerDomain;
-
- /**
- * The name of the owner of the API. See ownerDomain
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String ownerName;
-
- /**
- * The package of the owner of the API. See ownerDomain
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String packagePath;
-
- /**
- * Common parameters that apply across all apis.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.Map parameters;
-
- /**
- * The protocol described by this document.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String protocol;
-
- /**
- * The version of the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String revision;
-
- /**
- * The root URL under which all API services live.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String rootUrl;
-
- /**
- * The path for JSON-RPC requests.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String rpcPath;
-
- /**
- * [DEPRECATED] The URL for JSON-RPC requests.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String rpcUrl;
-
- /**
- * The schemas for this API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.Map schemas;
-
- /**
- * The title of the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String title;
-
- /**
- * The version of the API.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String version;
-
- /**
- * Authentication information.
- * @return value or {@code null} for none
- */
- public Auth getAuth() {
- return auth;
- }
-
- /**
- * Authentication information.
- * @param auth auth or {@code null} for none
- */
- public RpcDescription setAuth(Auth auth) {
- this.auth = auth;
- return this;
- }
-
- /**
- * Indicates how the API name should be capitalized and split into various parts. Useful for
- * generating pretty class names.
- * @return value or {@code null} for none
- */
- public java.lang.String getCanonicalName() {
- return canonicalName;
- }
-
- /**
- * Indicates how the API name should be capitalized and split into various parts. Useful for
- * generating pretty class names.
- * @param canonicalName canonicalName or {@code null} for none
- */
- public RpcDescription setCanonicalName(java.lang.String canonicalName) {
- this.canonicalName = canonicalName;
- return this;
- }
-
- /**
- * The description of the API.
- * @return value or {@code null} for none
- */
- public java.lang.String getDescription() {
- return description;
- }
-
- /**
- * The description of the API.
- * @param description description or {@code null} for none
- */
- public RpcDescription setDescription(java.lang.String description) {
- this.description = description;
- return this;
- }
-
- /**
- * Indicate the version of the Discovery API used to generate this doc.
- * @return value or {@code null} for none
- */
- public java.lang.String getDiscoveryVersion() {
- return discoveryVersion;
- }
-
- /**
- * Indicate the version of the Discovery API used to generate this doc.
- * @param discoveryVersion discoveryVersion or {@code null} for none
- */
- public RpcDescription setDiscoveryVersion(java.lang.String discoveryVersion) {
- this.discoveryVersion = discoveryVersion;
- return this;
- }
-
- /**
- * A link to human readable documentation for the API.
- * @return value or {@code null} for none
- */
- public java.lang.String getDocumentationLink() {
- return documentationLink;
- }
-
- /**
- * A link to human readable documentation for the API.
- * @param documentationLink documentationLink or {@code null} for none
- */
- public RpcDescription setDocumentationLink(java.lang.String documentationLink) {
- this.documentationLink = documentationLink;
- return this;
- }
-
- /**
- * The ETag for this response.
- * @return value or {@code null} for none
- */
- public java.lang.String getEtag() {
- return etag;
- }
-
- /**
- * The ETag for this response.
- * @param etag etag or {@code null} for none
- */
- public RpcDescription setEtag(java.lang.String etag) {
- this.etag = etag;
- return this;
- }
-
- /**
- * Enable exponential backoff for suitable methods in the generated clients.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getExponentialBackoffDefault() {
- return exponentialBackoffDefault;
- }
-
- /**
- * Enable exponential backoff for suitable methods in the generated clients.
- * @param exponentialBackoffDefault exponentialBackoffDefault or {@code null} for none
- */
- public RpcDescription setExponentialBackoffDefault(java.lang.Boolean exponentialBackoffDefault) {
- this.exponentialBackoffDefault = exponentialBackoffDefault;
- return this;
- }
-
- /**
- * A list of supported features for this API.
- * @return value or {@code null} for none
- */
- public java.util.List getFeatures() {
- return features;
- }
-
- /**
- * A list of supported features for this API.
- * @param features features or {@code null} for none
- */
- public RpcDescription setFeatures(java.util.List features) {
- this.features = features;
- return this;
- }
-
- /**
- * Links to 16x16 and 32x32 icons representing the API.
- * @return value or {@code null} for none
- */
- public Icons getIcons() {
- return icons;
- }
-
- /**
- * Links to 16x16 and 32x32 icons representing the API.
- * @param icons icons or {@code null} for none
- */
- public RpcDescription setIcons(Icons icons) {
- this.icons = icons;
- return this;
- }
-
- /**
- * The ID of this API.
- * @return value or {@code null} for none
- */
- public java.lang.String getId() {
- return id;
- }
-
- /**
- * The ID of this API.
- * @param id id or {@code null} for none
- */
- public RpcDescription setId(java.lang.String id) {
- this.id = id;
- return this;
- }
-
- /**
- * The kind for this response.
- * @return value or {@code null} for none
- */
- public java.lang.String getKind() {
- return kind;
- }
-
- /**
- * The kind for this response.
- * @param kind kind or {@code null} for none
- */
- public RpcDescription setKind(java.lang.String kind) {
- this.kind = kind;
- return this;
- }
-
- /**
- * Labels for the status of this API, such as labs or deprecated.
- * @return value or {@code null} for none
- */
- public java.util.List getLabels() {
- return labels;
- }
-
- /**
- * Labels for the status of this API, such as labs or deprecated.
- * @param labels labels or {@code null} for none
- */
- public RpcDescription setLabels(java.util.List labels) {
- this.labels = labels;
- return this;
- }
-
- /**
- * API-level methods for this API.
- * @return value or {@code null} for none
- */
- public java.util.Map getMethods() {
- return methods;
- }
-
- /**
- * API-level methods for this API.
- * @param methods methods or {@code null} for none
- */
- public RpcDescription setMethods(java.util.Map methods) {
- this.methods = methods;
- return this;
- }
-
- /**
- * The name of this API.
- * @return value or {@code null} for none
- */
- public java.lang.String getName() {
- return name;
- }
-
- /**
- * The name of this API.
- * @param name name or {@code null} for none
- */
- public RpcDescription setName(java.lang.String name) {
- this.name = name;
- return this;
- }
-
- /**
- * The domain of the owner of the API. Together with the ownerName and a packagePath values, this
- * can be used to generate a library for the API which would have a unique fully qualified name.
- * @return value or {@code null} for none
- */
- public java.lang.String getOwnerDomain() {
- return ownerDomain;
- }
-
- /**
- * The domain of the owner of the API. Together with the ownerName and a packagePath values, this
- * can be used to generate a library for the API which would have a unique fully qualified name.
- * @param ownerDomain ownerDomain or {@code null} for none
- */
- public RpcDescription setOwnerDomain(java.lang.String ownerDomain) {
- this.ownerDomain = ownerDomain;
- return this;
- }
-
- /**
- * The name of the owner of the API. See ownerDomain
- * @return value or {@code null} for none
- */
- public java.lang.String getOwnerName() {
- return ownerName;
- }
-
- /**
- * The name of the owner of the API. See ownerDomain
- * @param ownerName ownerName or {@code null} for none
- */
- public RpcDescription setOwnerName(java.lang.String ownerName) {
- this.ownerName = ownerName;
- return this;
- }
-
- /**
- * The package of the owner of the API. See ownerDomain
- * @return value or {@code null} for none
- */
- public java.lang.String getPackagePath() {
- return packagePath;
- }
-
- /**
- * The package of the owner of the API. See ownerDomain
- * @param packagePath packagePath or {@code null} for none
- */
- public RpcDescription setPackagePath(java.lang.String packagePath) {
- this.packagePath = packagePath;
- return this;
- }
-
- /**
- * Common parameters that apply across all apis.
- * @return value or {@code null} for none
- */
- public java.util.Map getParameters() {
- return parameters;
- }
-
- /**
- * Common parameters that apply across all apis.
- * @param parameters parameters or {@code null} for none
- */
- public RpcDescription setParameters(java.util.Map parameters) {
- this.parameters = parameters;
- return this;
- }
-
- /**
- * The protocol described by this document.
- * @return value or {@code null} for none
- */
- public java.lang.String getProtocol() {
- return protocol;
- }
-
- /**
- * The protocol described by this document.
- * @param protocol protocol or {@code null} for none
- */
- public RpcDescription setProtocol(java.lang.String protocol) {
- this.protocol = protocol;
- return this;
- }
-
- /**
- * The version of the API.
- * @return value or {@code null} for none
- */
- public java.lang.String getRevision() {
- return revision;
- }
-
- /**
- * The version of the API.
- * @param revision revision or {@code null} for none
- */
- public RpcDescription setRevision(java.lang.String revision) {
- this.revision = revision;
- return this;
- }
-
- /**
- * The root URL under which all API services live.
- * @return value or {@code null} for none
- */
- public java.lang.String getRootUrl() {
- return rootUrl;
- }
-
- /**
- * The root URL under which all API services live.
- * @param rootUrl rootUrl or {@code null} for none
- */
- public RpcDescription setRootUrl(java.lang.String rootUrl) {
- this.rootUrl = rootUrl;
- return this;
- }
-
- /**
- * The path for JSON-RPC requests.
- * @return value or {@code null} for none
- */
- public java.lang.String getRpcPath() {
- return rpcPath;
- }
-
- /**
- * The path for JSON-RPC requests.
- * @param rpcPath rpcPath or {@code null} for none
- */
- public RpcDescription setRpcPath(java.lang.String rpcPath) {
- this.rpcPath = rpcPath;
- return this;
- }
-
- /**
- * [DEPRECATED] The URL for JSON-RPC requests.
- * @return value or {@code null} for none
- */
- public java.lang.String getRpcUrl() {
- return rpcUrl;
- }
-
- /**
- * [DEPRECATED] The URL for JSON-RPC requests.
- * @param rpcUrl rpcUrl or {@code null} for none
- */
- public RpcDescription setRpcUrl(java.lang.String rpcUrl) {
- this.rpcUrl = rpcUrl;
- return this;
- }
-
- /**
- * The schemas for this API.
- * @return value or {@code null} for none
- */
- public java.util.Map getSchemas() {
- return schemas;
- }
-
- /**
- * The schemas for this API.
- * @param schemas schemas or {@code null} for none
- */
- public RpcDescription setSchemas(java.util.Map schemas) {
- this.schemas = schemas;
- return this;
- }
-
- /**
- * The title of the API.
- * @return value or {@code null} for none
- */
- public java.lang.String getTitle() {
- return title;
- }
-
- /**
- * The title of the API.
- * @param title title or {@code null} for none
- */
- public RpcDescription setTitle(java.lang.String title) {
- this.title = title;
- return this;
- }
-
- /**
- * The version of the API.
- * @return value or {@code null} for none
- */
- public java.lang.String getVersion() {
- return version;
- }
-
- /**
- * The version of the API.
- * @param version version or {@code null} for none
- */
- public RpcDescription setVersion(java.lang.String version) {
- this.version = version;
- return this;
- }
-
- @Override
- public RpcDescription set(String fieldName, Object value) {
- return (RpcDescription) super.set(fieldName, value);
- }
-
- @Override
- public RpcDescription clone() {
- return (RpcDescription) super.clone();
- }
-
- /**
- * Authentication information.
- */
- public static final class Auth extends com.google.api.client.json.GenericJson {
-
- /**
- * OAuth 2.0 authentication information.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private Oauth2 oauth2;
-
- /**
- * OAuth 2.0 authentication information.
- * @return value or {@code null} for none
- */
- public Oauth2 getOauth2() {
- return oauth2;
- }
-
- /**
- * OAuth 2.0 authentication information.
- * @param oauth2 oauth2 or {@code null} for none
- */
- public Auth setOauth2(Oauth2 oauth2) {
- this.oauth2 = oauth2;
- return this;
- }
-
- @Override
- public Auth set(String fieldName, Object value) {
- return (Auth) super.set(fieldName, value);
- }
-
- @Override
- public Auth clone() {
- return (Auth) super.clone();
- }
-
- /**
- * OAuth 2.0 authentication information.
- */
- public static final class Oauth2 extends com.google.api.client.json.GenericJson {
-
- /**
- * Available OAuth 2.0 scopes.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.Map scopes;
-
- static {
- // hack to force ProGuard to consider ScopesElement used, since otherwise it would be stripped out
- // see http://code.google.com/p/google-api-java-client/issues/detail?id=528
- com.google.api.client.util.Data.nullOf(ScopesElement.class);
- }
-
- /**
- * Available OAuth 2.0 scopes.
- * @return value or {@code null} for none
- */
- public java.util.Map getScopes() {
- return scopes;
- }
-
- /**
- * Available OAuth 2.0 scopes.
- * @param scopes scopes or {@code null} for none
- */
- public Oauth2 setScopes(java.util.Map scopes) {
- this.scopes = scopes;
- return this;
- }
-
- @Override
- public Oauth2 set(String fieldName, Object value) {
- return (Oauth2) super.set(fieldName, value);
- }
-
- @Override
- public Oauth2 clone() {
- return (Oauth2) super.clone();
- }
-
- /**
- * The scope value.
- */
- public static final class ScopesElement extends com.google.api.client.json.GenericJson {
-
- /**
- * Description of scope.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String description;
-
- /**
- * Description of scope.
- * @return value or {@code null} for none
- */
- public java.lang.String getDescription() {
- return description;
- }
-
- /**
- * Description of scope.
- * @param description description or {@code null} for none
- */
- public ScopesElement setDescription(java.lang.String description) {
- this.description = description;
- return this;
- }
-
- @Override
- public ScopesElement set(String fieldName, Object value) {
- return (ScopesElement) super.set(fieldName, value);
- }
-
- @Override
- public ScopesElement clone() {
- return (ScopesElement) super.clone();
- }
-
- }
- }
- }
-
- /**
- * Links to 16x16 and 32x32 icons representing the API.
- */
- public static final class Icons extends com.google.api.client.json.GenericJson {
-
- /**
- * The URL of the 16x16 icon.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String x16;
-
- /**
- * The URL of the 32x32 icon.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String x32;
-
- /**
- * The URL of the 16x16 icon.
- * @return value or {@code null} for none
- */
- public java.lang.String getX16() {
- return x16;
- }
-
- /**
- * The URL of the 16x16 icon.
- * @param x16 x16 or {@code null} for none
- */
- public Icons setX16(java.lang.String x16) {
- this.x16 = x16;
- return this;
- }
-
- /**
- * The URL of the 32x32 icon.
- * @return value or {@code null} for none
- */
- public java.lang.String getX32() {
- return x32;
- }
-
- /**
- * The URL of the 32x32 icon.
- * @param x32 x32 or {@code null} for none
- */
- public Icons setX32(java.lang.String x32) {
- this.x32 = x32;
- return this;
- }
-
- @Override
- public Icons set(String fieldName, Object value) {
- return (Icons) super.set(fieldName, value);
- }
-
- @Override
- public Icons clone() {
- return (Icons) super.clone();
- }
-
- }
-
-}
diff --git a/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcMethod.java b/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcMethod.java
deleted file mode 100644
index f8259217..00000000
--- a/discovery-client/src/main/java/com/google/api/services/discovery/model/RpcMethod.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-/*
- * This code was generated by https://code.google.com/p/google-apis-client-generator/
- * (build: 2015-11-16 19:10:01 UTC)
- * on 2015-11-19 at 17:34:48 UTC
- * Modify at your own risk.
- */
-
-package com.google.api.services.discovery.model;
-
-/**
- * Model definition for RpcMethod.
- *
- *
This is the Java data model class that specifies how to parse/serialize into the JSON that is
- * transmitted over HTTP when working with the APIs Discovery Service. For a detailed explanation
- * see:
- * http://code.google.com/p/google-http-java-client/wiki/JSON
- *
- *
- * @author Google, Inc.
- */
-@SuppressWarnings("javadoc")
-public final class RpcMethod extends com.google.api.client.json.GenericJson {
-
- /**
- * Whether the method can be made using an HTTP GET JSON-RPC request.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean allowGet;
-
- /**
- * Description of this method.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String description;
-
- /**
- * Does this method require sending the ETag along with the request.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean etagRequired;
-
- /**
- * A unique ID for this method. This property can be used to match methods between different
- * versions of Discovery.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String id;
-
- /**
- * Media upload parameters.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private MediaUpload mediaUpload;
-
- /**
- * Ordered list of required parameters, serves as a hint to clients on how to structure their
- * method signatures. The array is ordered such that the "most-significant" parameter appears
- * first.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.List parameterOrder;
-
- /**
- * Description for all parameters in this method.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.Map parameters;
-
- static {
- // hack to force ProGuard to consider JsonSchema used, since otherwise it would be stripped out
- // see http://code.google.com/p/google-api-java-client/issues/detail?id=528
- com.google.api.client.util.Data.nullOf(JsonSchema.class);
- }
-
- /**
- * The schema for the response.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private Returns returns;
-
- /**
- * OAuth 2.0 scopes applicable to this method.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.List scopes;
-
- /**
- * Whether this method supports media download.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean supportsMediaDownload;
-
- /**
- * Whether this method supports media upload.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean supportsMediaUpload;
-
- /**
- * Whether this method supports patch semantics.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean supportsPatch;
-
- /**
- * Whether this method supports subscriptions.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean supportsSubscription;
-
- /**
- * Indicates that downloads from this method should use the download service URL (i.e.
- * "/download"). Only applies if the method supports media download.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.Boolean useMediaDownloadService;
-
- /**
- * Whether the method can be made using an HTTP GET JSON-RPC request.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getAllowGet() {
- return allowGet;
- }
-
- /**
- * Whether the method can be made using an HTTP GET JSON-RPC request.
- * @param allowGet allowGet or {@code null} for none
- */
- public RpcMethod setAllowGet(java.lang.Boolean allowGet) {
- this.allowGet = allowGet;
- return this;
- }
-
- /**
- * Description of this method.
- * @return value or {@code null} for none
- */
- public java.lang.String getDescription() {
- return description;
- }
-
- /**
- * Description of this method.
- * @param description description or {@code null} for none
- */
- public RpcMethod setDescription(java.lang.String description) {
- this.description = description;
- return this;
- }
-
- /**
- * Does this method require sending the ETag along with the request.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getEtagRequired() {
- return etagRequired;
- }
-
- /**
- * Does this method require sending the ETag along with the request.
- * @param etagRequired etagRequired or {@code null} for none
- */
- public RpcMethod setEtagRequired(java.lang.Boolean etagRequired) {
- this.etagRequired = etagRequired;
- return this;
- }
-
- /**
- * A unique ID for this method. This property can be used to match methods between different
- * versions of Discovery.
- * @return value or {@code null} for none
- */
- public java.lang.String getId() {
- return id;
- }
-
- /**
- * A unique ID for this method. This property can be used to match methods between different
- * versions of Discovery.
- * @param id id or {@code null} for none
- */
- public RpcMethod setId(java.lang.String id) {
- this.id = id;
- return this;
- }
-
- /**
- * Media upload parameters.
- * @return value or {@code null} for none
- */
- public MediaUpload getMediaUpload() {
- return mediaUpload;
- }
-
- /**
- * Media upload parameters.
- * @param mediaUpload mediaUpload or {@code null} for none
- */
- public RpcMethod setMediaUpload(MediaUpload mediaUpload) {
- this.mediaUpload = mediaUpload;
- return this;
- }
-
- /**
- * Ordered list of required parameters, serves as a hint to clients on how to structure their
- * method signatures. The array is ordered such that the "most-significant" parameter appears
- * first.
- * @return value or {@code null} for none
- */
- public java.util.List getParameterOrder() {
- return parameterOrder;
- }
-
- /**
- * Ordered list of required parameters, serves as a hint to clients on how to structure their
- * method signatures. The array is ordered such that the "most-significant" parameter appears
- * first.
- * @param parameterOrder parameterOrder or {@code null} for none
- */
- public RpcMethod setParameterOrder(java.util.List parameterOrder) {
- this.parameterOrder = parameterOrder;
- return this;
- }
-
- /**
- * Description for all parameters in this method.
- * @return value or {@code null} for none
- */
- public java.util.Map getParameters() {
- return parameters;
- }
-
- /**
- * Description for all parameters in this method.
- * @param parameters parameters or {@code null} for none
- */
- public RpcMethod setParameters(java.util.Map parameters) {
- this.parameters = parameters;
- return this;
- }
-
- /**
- * The schema for the response.
- * @return value or {@code null} for none
- */
- public Returns getReturns() {
- return returns;
- }
-
- /**
- * The schema for the response.
- * @param returns returns or {@code null} for none
- */
- public RpcMethod setReturns(Returns returns) {
- this.returns = returns;
- return this;
- }
-
- /**
- * OAuth 2.0 scopes applicable to this method.
- * @return value or {@code null} for none
- */
- public java.util.List getScopes() {
- return scopes;
- }
-
- /**
- * OAuth 2.0 scopes applicable to this method.
- * @param scopes scopes or {@code null} for none
- */
- public RpcMethod setScopes(java.util.List scopes) {
- this.scopes = scopes;
- return this;
- }
-
- /**
- * Whether this method supports media download.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getSupportsMediaDownload() {
- return supportsMediaDownload;
- }
-
- /**
- * Whether this method supports media download.
- * @param supportsMediaDownload supportsMediaDownload or {@code null} for none
- */
- public RpcMethod setSupportsMediaDownload(java.lang.Boolean supportsMediaDownload) {
- this.supportsMediaDownload = supportsMediaDownload;
- return this;
- }
-
- /**
- * Whether this method supports media upload.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getSupportsMediaUpload() {
- return supportsMediaUpload;
- }
-
- /**
- * Whether this method supports media upload.
- * @param supportsMediaUpload supportsMediaUpload or {@code null} for none
- */
- public RpcMethod setSupportsMediaUpload(java.lang.Boolean supportsMediaUpload) {
- this.supportsMediaUpload = supportsMediaUpload;
- return this;
- }
-
- /**
- * Whether this method supports patch semantics.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getSupportsPatch() {
- return supportsPatch;
- }
-
- /**
- * Whether this method supports patch semantics.
- * @param supportsPatch supportsPatch or {@code null} for none
- */
- public RpcMethod setSupportsPatch(java.lang.Boolean supportsPatch) {
- this.supportsPatch = supportsPatch;
- return this;
- }
-
- /**
- * Whether this method supports subscriptions.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getSupportsSubscription() {
- return supportsSubscription;
- }
-
- /**
- * Whether this method supports subscriptions.
- * @param supportsSubscription supportsSubscription or {@code null} for none
- */
- public RpcMethod setSupportsSubscription(java.lang.Boolean supportsSubscription) {
- this.supportsSubscription = supportsSubscription;
- return this;
- }
-
- /**
- * Indicates that downloads from this method should use the download service URL (i.e.
- * "/download"). Only applies if the method supports media download.
- * @return value or {@code null} for none
- */
- public java.lang.Boolean getUseMediaDownloadService() {
- return useMediaDownloadService;
- }
-
- /**
- * Indicates that downloads from this method should use the download service URL (i.e.
- * "/download"). Only applies if the method supports media download.
- * @param useMediaDownloadService useMediaDownloadService or {@code null} for none
- */
- public RpcMethod setUseMediaDownloadService(java.lang.Boolean useMediaDownloadService) {
- this.useMediaDownloadService = useMediaDownloadService;
- return this;
- }
-
- @Override
- public RpcMethod set(String fieldName, Object value) {
- return (RpcMethod) super.set(fieldName, value);
- }
-
- @Override
- public RpcMethod clone() {
- return (RpcMethod) super.clone();
- }
-
- /**
- * Media upload parameters.
- */
- public static final class MediaUpload extends com.google.api.client.json.GenericJson {
-
- /**
- * MIME Media Ranges for acceptable media uploads to this method.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.util.List accept;
-
- /**
- * Maximum size of a media upload, such as "1MB", "2GB" or "3TB".
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String maxSize;
-
- /**
- * MIME Media Ranges for acceptable media uploads to this method.
- * @return value or {@code null} for none
- */
- public java.util.List getAccept() {
- return accept;
- }
-
- /**
- * MIME Media Ranges for acceptable media uploads to this method.
- * @param accept accept or {@code null} for none
- */
- public MediaUpload setAccept(java.util.List accept) {
- this.accept = accept;
- return this;
- }
-
- /**
- * Maximum size of a media upload, such as "1MB", "2GB" or "3TB".
- * @return value or {@code null} for none
- */
- public java.lang.String getMaxSize() {
- return maxSize;
- }
-
- /**
- * Maximum size of a media upload, such as "1MB", "2GB" or "3TB".
- * @param maxSize maxSize or {@code null} for none
- */
- public MediaUpload setMaxSize(java.lang.String maxSize) {
- this.maxSize = maxSize;
- return this;
- }
-
- @Override
- public MediaUpload set(String fieldName, Object value) {
- return (MediaUpload) super.set(fieldName, value);
- }
-
- @Override
- public MediaUpload clone() {
- return (MediaUpload) super.clone();
- }
-
- }
-
- /**
- * The schema for the response.
- */
- public static final class Returns extends com.google.api.client.json.GenericJson {
-
- /**
- * Schema ID for the response schema.
- * The value may be {@code null}.
- */
- @com.google.api.client.util.Key
- private java.lang.String $ref;
-
- /**
- * Schema ID for the response schema.
- * @return value or {@code null} for none
- */
- public java.lang.String get$ref() {
- return $ref;
- }
-
- /**
- * Schema ID for the response schema.
- * @param $ref $ref or {@code null} for none
- */
- public Returns set$ref(java.lang.String $ref) {
- this.$ref = $ref;
- return this;
- }
-
- @Override
- public Returns set(String fieldName, Object value) {
- return (Returns) super.set(fieldName, value);
- }
-
- @Override
- public Returns clone() {
- return (Returns) super.clone();
- }
-
- }
-
-}
diff --git a/endpoints-framework-all/build.gradle b/endpoints-framework-all/build.gradle
index 73394894..22aace28 100644
--- a/endpoints-framework-all/build.gradle
+++ b/endpoints-framework-all/build.gradle
@@ -1,5 +1,6 @@
plugins {
- id 'com.github.johnrengelman.shadow' version '1.2.3'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+ id 'java-library'
}
configurations {
@@ -16,7 +17,7 @@ jar {
def repackagedDir = 'endpoints.repackaged'
shadowJar {
- classifier = null
+ archiveClassifier = null
relocate 'org.apache', "${repackagedDir}.org.apache"
relocate 'org.yaml', "${repackagedDir}.org.yaml"
relocate 'org.joda', "${repackagedDir}.org.joda"
@@ -25,6 +26,7 @@ shadowJar {
relocate 'com.google.common', "${repackagedDir}.com.google.common"
relocate 'com.google.api.client', "${repackagedDir}.com.google.api.client"
relocate 'org.slf4j', "${repackagedDir}.org.slf4j"
+ relocate 'com.google.thirdparty', "${repackagedDir}.com.google.thirdparty"
dependencies {
exclude(dependency('com.google.appengine:appengine-api-1.0-sdk:.*'))
@@ -37,9 +39,9 @@ artifacts {
}
dependencies {
- include project(':endpoints-framework')
- compile group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: appengineVersion
- compile group: 'javax.servlet', name: 'servlet-api', version: servletVersion
+ compileOnly project(':endpoints-framework')
+ api group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: appengineVersion
+ api group: 'javax.servlet', name: 'servlet-api', version: servletVersion
}
configureMaven(project, 'Endpoints Framework', 'A framework for building RESTful web APIs.')
diff --git a/endpoints-framework-guice/build.gradle b/endpoints-framework-guice/build.gradle
index 851fdda1..6ba0566f 100644
--- a/endpoints-framework-guice/build.gradle
+++ b/endpoints-framework-guice/build.gradle
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+plugins {
+ id 'java-library'
+}
+
configureMaven(
project,
'Endpoints Framework Guice Extension',
@@ -21,10 +25,11 @@ configureMaven(
dependencies {
compileOnly project(':endpoints-framework')
- compile group: 'com.google.inject', name: 'guice', version: guiceVersion
- compile group: 'com.google.inject.extensions', name: 'guice-servlet', version: guiceVersion
+ api group: 'com.google.inject', name: 'guice', version: guiceVersion
+ api group: 'com.google.inject.extensions', name: 'guice-servlet', version: guiceVersion
- testCompile project(':test-utils')
- testCompile group: 'junit', name: 'junit', version: junitVersion
- testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
+ testImplementation project(':test-utils')
+ testImplementation project(':endpoints-framework')
+ testImplementation group: 'junit', name: 'junit', version: junitVersion
+ testImplementation group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
}
diff --git a/endpoints-framework-guice/src/main/java/com/google/api/server/spi/guice/EndpointsModule.java b/endpoints-framework-guice/src/main/java/com/google/api/server/spi/guice/EndpointsModule.java
index ee7814eb..694c7832 100644
--- a/endpoints-framework-guice/src/main/java/com/google/api/server/spi/guice/EndpointsModule.java
+++ b/endpoints-framework-guice/src/main/java/com/google/api/server/spi/guice/EndpointsModule.java
@@ -25,7 +25,6 @@
* this class and call one of the helpers in {@link #configureServlets()}.
*/
public class EndpointsModule extends ServletModule {
- private static final Logger logger = Logger.getLogger(EndpointsModule.class.getName());
/**
* Configure Endpoints given a list of service classes using {@link GuiceEndpointsServlet}.
*
@@ -36,40 +35,10 @@ public class EndpointsModule extends ServletModule {
*/
protected void configureEndpoints(
String urlPattern, Iterable extends Class>> serviceClasses) {
- configureEndpoints(urlPattern, serviceClasses, false);
- }
-
- /**
- * Configure Endpoints given a list of service classes.
- *
- * @deprecated the legacy servlet is no longer available.
- * @param urlPattern the URL pattern to configure the servlet on. For the legacy servlet, use
- * "/_ah/spi/*". For the new servlet, use "/_ah/api/*" if backwards compatibility is desired, or
- * any other pattern if compatibility is not an issue.
- * @param serviceClasses the list of backend classes to be included
- * @param useLegacyServlet whether or not to use the old style servlet
- */
- @Deprecated
- protected void configureEndpoints(
- String urlPattern, Iterable extends Class>> serviceClasses, boolean useLegacyServlet) {
ServletInitializationParameters initParameters = ServletInitializationParameters.builder()
.addServiceClasses(serviceClasses)
.build();
- configureEndpoints(urlPattern, initParameters, useLegacyServlet);
- }
-
- /**
- * Configure Endpoints given {@link ServletInitializationParameters} using
- * {@link GuiceEndpointsServlet}.
- *
- * @param urlPattern the URL pattern to configure the servlet on. For the legacy servlet, use
- * "/_ah/spi/*". For the new servlet, use "/_ah/api/*" if backwards compatibility is desired, or
- * any other pattern if compatibility is not an issue
- * @param initParameters the initialization parameters. Must include service classes to be useful
- */
- protected void configureEndpoints(
- String urlPattern, ServletInitializationParameters initParameters) {
- configureEndpoints(urlPattern, initParameters, false);
+ configureEndpoints(urlPattern, initParameters);
}
/**
@@ -79,15 +48,11 @@ protected void configureEndpoints(
* "/_ah/spi/*". For the new servlet, use "/_ah/api/*" if backwards compatibility is desired, or
* any other pattern if compatibility is not an issue
* @param initParameters the initialization parameters. Must include service classes to be useful
- * @param useLegacyServlet whether or not to use the old style servlet
*/
protected void configureEndpoints(
- String urlPattern, ServletInitializationParameters initParameters, boolean useLegacyServlet) {
+ String urlPattern, ServletInitializationParameters initParameters) {
bind(ServiceMap.class)
.toInstance(ServiceMap.create(binder(), initParameters.getServiceClasses()));
- if (useLegacyServlet) {
- logger.severe("the legacy servlet is no longer available.");
- }
super.serve(urlPattern).with(GuiceEndpointsServlet.class, initParameters.asMap());
}
}
diff --git a/endpoints-framework-guice/src/test/java/com/google/api/server/spi/guice/EndpointsModuleTest.java b/endpoints-framework-guice/src/test/java/com/google/api/server/spi/guice/EndpointsModuleTest.java
index 79f18087..ada9972a 100644
--- a/endpoints-framework-guice/src/test/java/com/google/api/server/spi/guice/EndpointsModuleTest.java
+++ b/endpoints-framework-guice/src/test/java/com/google/api/server/spi/guice/EndpointsModuleTest.java
@@ -54,7 +54,6 @@ public class EndpointsModuleTest {
private static final ServletInitializationParameters INIT_PARAMETERS =
ServletInitializationParameters.builder()
.addServiceClasses(SERVICES)
- .setRestricted(false)
.build();
private EndpointsModule module;
@@ -64,7 +63,7 @@ public void setUp() throws Exception {
@Override
protected void configureServlets() {
super.configureServlets();
- configureEndpoints(URL_PATTERN, INIT_PARAMETERS, true);
+ configureEndpoints(URL_PATTERN, INIT_PARAMETERS);
}
};
Elements.getElements(module);
@@ -82,8 +81,6 @@ public void testConfigureEndpoints_withInterceptor() {
assertEquals("Servlet not bound.", 1, visitor.linkedServlets.size());
LinkedServletBinding servletBinding = visitor.linkedServlets.get(0);
assertEquals("URL pattern does not match", URL_PATTERN, servletBinding.getPattern());
- assertEquals("Wrong initialization parameter provided", "false",
- servletBinding.getInitParams().get("restricted"));
assertNotNull("SystemService named provider not found.", visitor.systemServiceProvider);
ServiceMap serviceMap = (ServiceMap) visitor.systemServiceProvider.getProvider().get();
@@ -105,8 +102,6 @@ public void testConfigureEndpoints_withoutInterceptor() {
assertEquals("Servlet not bound.", 1, visitor.linkedServlets.size());
LinkedServletBinding servletBinding = visitor.linkedServlets.get(0);
assertEquals("URL pattern does not match", URL_PATTERN, servletBinding.getPattern());
- assertEquals("Wrong initialization parameter provided", "false",
- servletBinding.getInitParams().get("restricted"));
assertNotNull("SystemService named provider not found.", visitor.systemServiceProvider);
ServiceMap serviceMap = (ServiceMap) visitor.systemServiceProvider.getProvider().get();
@@ -116,64 +111,34 @@ public void testConfigureEndpoints_withoutInterceptor() {
services.toArray()[0].getClass());
}
- @Test
- public void testConfigureEndpoints_legacyServletWithServices() {
- testServletClassWithServices(true, GuiceEndpointsServlet.class);
- }
-
- @Test
- public void testConfigureEndpoints_newServletWithServices() {
- testServletClassWithServices(false, GuiceEndpointsServlet.class);
- }
-
@Test
public void testConfigureEndpoints_defaultServletWithServices() {
- testServletClassWithServices(null, GuiceEndpointsServlet.class);
- }
-
- @Test
- public void testConfigureEndpoints_legacyServletWithInitParams() {
- testServletClassWithInitParams(true, GuiceEndpointsServlet.class);
- }
-
- @Test
- public void testConfigureEndpoints_newServletWithInitParams() {
- testServletClassWithInitParams(false, GuiceEndpointsServlet.class);
+ testServletClassWithServices(GuiceEndpointsServlet.class);
}
@Test
public void testConfigureEndpoints_defaultServletWithInitParams() {
- testServletClassWithInitParams(null, GuiceEndpointsServlet.class);
+ testServletClassWithInitParams(GuiceEndpointsServlet.class);
}
- private void testServletClassWithServices(final Boolean servletFlag, Class> expectedClass) {
+ private void testServletClassWithServices(Class> expectedClass) {
testServletClass(new EndpointsModule() {
@Override
protected void configureServlets() {
super.configureServlets();
- if (servletFlag == null) {
- configureEndpoints(URL_PATTERN, SERVICES);
- } else {
- configureEndpoints(URL_PATTERN, SERVICES, servletFlag);
- }
+ configureEndpoints(URL_PATTERN, SERVICES);
}
}, expectedClass);
}
- private void testServletClassWithInitParams(final Boolean servletFlag, Class> expectedClass) {
+ private void testServletClassWithInitParams(Class> expectedClass) {
testServletClass(new EndpointsModule() {
@Override
protected void configureServlets() {
super.configureServlets();
- if (servletFlag == null) {
- configureEndpoints(URL_PATTERN, ServletInitializationParameters.builder()
- .addServiceClasses(SERVICES)
- .build());
- } else {
- configureEndpoints(URL_PATTERN, ServletInitializationParameters.builder()
- .addServiceClasses(SERVICES)
- .build(), servletFlag);
- }
+ configureEndpoints(URL_PATTERN, ServletInitializationParameters.builder()
+ .addServiceClasses(SERVICES)
+ .build());
}
}, expectedClass);
}
@@ -199,7 +164,7 @@ public void testConfigureEndpoints_defaultInitParameters() {
@Override
protected void configureServlets() {
super.configureServlets();
- configureEndpoints(URL_PATTERN, SERVICES, true);
+ configureEndpoints(URL_PATTERN, SERVICES);
}
};
Injector injector = Guice.createInjector(module, new DummyModule());
@@ -212,8 +177,6 @@ protected void configureServlets() {
assertEquals("Servlet not bound.", 1, visitor.linkedServlets.size());
LinkedServletBinding servletBinding = visitor.linkedServlets.get(0);
assertEquals("URL pattern does not match", URL_PATTERN, servletBinding.getPattern());
- assertEquals("Wrong initialization parameter provided", "true",
- servletBinding.getInitParams().get("restricted"));
assertNotNull("SystemService named provider not found.", visitor.systemServiceProvider);
ServiceMap serviceMap = (ServiceMap) visitor.systemServiceProvider.getProvider().get();
diff --git a/endpoints-framework-tools/build.gradle b/endpoints-framework-tools/build.gradle
index ed9db8d9..9c739507 100644
--- a/endpoints-framework-tools/build.gradle
+++ b/endpoints-framework-tools/build.gradle
@@ -30,12 +30,13 @@ apply plugin: 'application'
mainClassName = 'com.google.api.server.spi.tools.EndpointsTool'
dependencies {
- compile project(':endpoints-framework')
- compile group: 'com.google.appengine', name: 'appengine-tools-sdk', version: appengineVersion
+ compileOnly project(':discovery-client')
+ api project(':endpoints-framework')
+ api group: 'com.google.appengine', name: 'appengine-tools-sdk', version: appengineVersion
- testCompile project(':test-utils')
- testCompile group: 'junit', name: 'junit', version: junitVersion
- testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
- testCompile group: 'com.google.truth', name: 'truth', version: truthVersion
- testCompile group: 'org.springframework', name: 'spring-test', version: springtestVersion
+ testImplementation project(':test-utils')
+ testImplementation group: 'junit', name: 'junit', version: junitVersion
+ testImplementation group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
+ testImplementation group: 'com.google.truth', name: 'truth', version: truthVersion
+ testImplementation group: 'org.springframework', name: 'spring-test', version: springtestVersion
}
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsTool.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsTool.java
index ded5a58f..862be3b9 100644
--- a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsTool.java
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsTool.java
@@ -51,8 +51,10 @@ public EndpointsTool() {
actions = new LinkedHashMap<>();
actions.put(GetDiscoveryDocAction.NAME, new GetDiscoveryDocAction());
actions.put(GetClientLibAction.NAME, new GetClientLibAction());
+ actions.put(GetClientSrcAction.NAME, new GetClientSrcAction());
actions.put(GenApiConfigAction.NAME, new GenApiConfigAction());
actions.put(GenClientLibAction.NAME, new GenClientLibAction());
+ actions.put(GenClientSrcAction.NAME, new GenClientSrcAction());
actions.put(GetOpenApiDocAction.NAME, new GetOpenApiDocAction());
actions.put(GetOpenApiDocAction.LEGACY_NAME,
new GetOpenApiDocAction(GetOpenApiDocAction.LEGACY_NAME, false));
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsToolAction.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsToolAction.java
index 2380a822..49e775f4 100644
--- a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsToolAction.java
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/EndpointsToolAction.java
@@ -214,10 +214,6 @@ protected String getBuildSystem(Option buildSystemOption) {
return getOptionOrDefault(buildSystemOption, DEFAULT_BUILD_SYSTEM);
}
- protected String getFormat(Option formatOption) {
- return getOptionOrDefault(formatOption, DEFAULT_FORMAT);
- }
-
protected boolean getDebug(Option debugOption) {
return debugOption.getValue() != null;
}
@@ -406,13 +402,6 @@ public void setHelpDisplayNeeded(boolean helpDisplayNeeded) {
this.helpDisplayNeeded = helpDisplayNeeded;
}
- /**
- * Return the example string which will be displayed in the usage.
- */
- public String getExampleString() {
- return exampleString;
- }
-
/**
* Set the example string which will be displayed in the usage.
*/
@@ -467,6 +456,17 @@ public static EndpointsOption makeVisibleNonFlagOption(
return new EndpointsOption(shortName, longName, false, true, placeHolderValue, description);
}
+ public static EndpointsOption makeVisibleFlagOption(
+ @Nullable String longName,
+ @Nullable String description) {
+ return new EndpointsOption(null, longName, true, true, null, description) {
+ @Override
+ public void apply() {
+ getValues().add("true");
+ }
+ };
+ }
+
public static EndpointsOption makeInvisibleFlagOption(
@Nullable String shortName,
@Nullable String longName) {
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GenClientSrcAction.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GenClientSrcAction.java
new file mode 100644
index 00000000..bffdfefe
--- /dev/null
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GenClientSrcAction.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import com.google.appengine.tools.util.Option;
+
+/**
+ * Command to generate a client API source code from a Discovery document.
+ */
+public class GenClientSrcAction extends EndpointsToolAction {
+
+ // name of this command
+ public static final String NAME = "gen-client-src";
+
+ private Option languageOption = makeLanguageOption();
+ private Option outputOption = makeOutputOption();
+
+ public GenClientSrcAction() {
+ super(NAME);
+ setOptions(Arrays.asList(languageOption, outputOption));
+ setShortDescription("Generates a client API source code");
+ setHelpDisplayNeeded(false);
+ }
+
+ @Override
+ public boolean execute() throws IOException {
+ if (getArgs().size() != 1) {
+ return false;
+ }
+ genClientSrcFromFile(getLanguage(languageOption), getOutputPath(outputOption), getArgs().get(0));
+ return true;
+ }
+
+ /**
+ * Generates a client library for an API.
+ * @param language Language of the client library.
+ * @param outputDirPath Directory to write generated client library into
+ * @param discoveryDoc Discovery doc file
+ */
+ public Object genClientSrcFromFile(String language, String outputDirPath, String discoveryDoc)
+ throws IOException {
+ ClientLibGenerator generator = new LocalClientLibGenerator();
+ generator.generateClientLib(discoveryDoc, language, "", "", new File(outputDirPath));
+ return null;
+ }
+
+ @Override
+ public String getUsageString() {
+ return NAME + " ";
+ }
+}
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetClientSrcAction.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetClientSrcAction.java
new file mode 100644
index 00000000..85221409
--- /dev/null
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetClientSrcAction.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import com.google.api.server.spi.config.ApiConfigException;
+import com.google.appengine.tools.util.Option;
+
+/**
+ * Command that combines 3 other ones and generates client API source code from service classes.
+ */
+public class GetClientSrcAction extends EndpointsToolAction {
+
+ // name of this command
+ public static final String NAME = "get-client-src";
+
+ private Option classPathOption = makeClassPathOption();
+ private Option languageOption = makeLanguageOption();
+ private Option outputOption = makeOutputOption();
+ private Option warOption = makeWarOption();
+ private Option debugOption = makeDebugOption();
+ private Option hostnameOption = makeHostnameOption();
+ private Option basePathOption = makeBasePathOption();
+
+ public GetClientSrcAction() {
+ super(NAME);
+ setOptions(Arrays.asList(classPathOption, languageOption, outputOption, warOption,
+ debugOption, hostnameOption, basePathOption));
+ setShortDescription("Generates client source code");
+ setExampleString(" get-client-src --language=java "
+ + "com.google.devrel.samples.ttt.spi.BoardV1 com.google.devrel.samples.ttt.spi.ScoresV1");
+ setHelpDisplayNeeded(true);
+ }
+
+ @Override
+ public boolean execute() throws ClassNotFoundException, IOException, ApiConfigException {
+ String warPath = getWarPath(warOption);
+ List serviceClassNames = getServiceClassNames(warPath);
+ if (serviceClassNames.isEmpty()) {
+ return false;
+ }
+ getClientSrc(computeClassPath(warPath, getClassPath(classPathOption)),
+ getLanguage(languageOption), getOutputPath(outputOption), serviceClassNames,
+ getHostname(hostnameOption, warPath), getBasePath(basePathOption),
+ getDebug(debugOption)
+ );
+ return true;
+ }
+
+ /**
+ * Generates a Java client API source code for an API. Combines the steps of generating API
+ * configuration, generating Discovery doc and generating client source code into one.
+ * @param classPath Class path to load service classes and their dependencies
+ * @param language Language of the client library. Only "java" is supported right now
+ * @param outputDirPath Directory to write output files into
+ * @param serviceClassNames Array of service class names of the API
+ * @param hostname The hostname to use
+ * @param basePath The base path to use
+ * @param debug Whether or not to output intermediate output files
+ */
+ public Object getClientSrc(URL[] classPath, String language, String outputDirPath,
+ List serviceClassNames, String hostname, String basePath,
+ boolean debug) throws ClassNotFoundException, IOException, ApiConfigException {
+ Map discoveryDocs = new GetDiscoveryDocAction().getDiscoveryDoc(
+ classPath, outputDirPath, serviceClassNames, hostname, basePath, debug /* outputToDisk */);
+ for (Map.Entry entry : discoveryDocs.entrySet()) {
+ new GenClientSrcAction().genClientSrcFromFile(language, outputDirPath, entry.getValue());
+ }
+ return null;
+ }
+
+ @Override
+ public String getUsageString() {
+ return NAME + " ...";
+ }
+}
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetDiscoveryDocAction.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetDiscoveryDocAction.java
index 88bc0fe2..b5a26d3f 100644
--- a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetDiscoveryDocAction.java
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetDiscoveryDocAction.java
@@ -60,13 +60,12 @@ public class GetDiscoveryDocAction extends EndpointsToolAction {
private Option classPathOption = makeClassPathOption();
private Option outputOption = makeOutputOption();
private Option warOption = makeWarOption();
- private Option debugOption = makeDebugOption();
private Option hostnameOption = makeHostnameOption();
private Option basePathOption = makeBasePathOption();
public GetDiscoveryDocAction() {
super(NAME);
- setOptions(Arrays.asList(classPathOption, outputOption, warOption, debugOption, hostnameOption,
+ setOptions(Arrays.asList(classPathOption, outputOption, warOption, hostnameOption,
basePathOption));
setShortDescription("Generates discovery documents");
setExampleString(" get-discovery-doc "
@@ -141,7 +140,7 @@ apiConfigs, new DiscoveryContext().setHostname(hostname).setBasePath(basePath),
outputDir + "/" + key.getName() + "-" + key.getVersion() + "-rest.discovery";
String docString = writer.writeValueAsString(entry.getValue());
if (outputToDisk) {
- Files.write(docString, new File(discoveryDocFilePath), UTF_8);
+ Files.asCharSink(new File(discoveryDocFilePath), UTF_8).write(docString);
System.out.println("API Discovery Document written to " + discoveryDocFilePath);
}
builder.put(discoveryDocFilePath, docString);
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetOpenApiDocAction.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetOpenApiDocAction.java
index dfcf47ac..819881b6 100644
--- a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetOpenApiDocAction.java
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/GetOpenApiDocAction.java
@@ -15,6 +15,7 @@
*/
package com.google.api.server.spi.tools;
+import static com.google.api.server.spi.tools.EndpointsToolAction.EndpointsOption.makeVisibleFlagOption;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.api.server.spi.ServiceContext;
@@ -52,6 +53,23 @@ public class GetOpenApiDocAction extends EndpointsToolAction {
private Option warOption = makeWarOption();
private Option hostnameOption = makeHostnameOption();
private Option basePathOption = makeBasePathOption();
+ private Option titleOption = makeTitleOption();
+ private Option descriptionOption = makeDescriptionOption();
+ private Option apiNameOption = makeApiNameOption();
+ private Option tagTemplateOption = makeTagTemplateOption();
+ private Option operationIdTemplateOption = makeOperationIdTemplateOption();
+ private Option addGoogleJsonErrorAsDefaultResponseOption = makeVisibleFlagOption(
+ "addGoogleJsonErrorAsDefaultResponse", "Add GoogleJsonError as default response"
+ );
+ private Option addErrorCodesForServiceExceptionsOption = makeVisibleFlagOption(
+ "addErrorCodesForServiceExceptions", "Add GoogleJsonError for codes in ServiceExceptions"
+ );
+ private Option extractCommonParametersAsRefsOption = makeVisibleFlagOption(
+ "extractCommonParametersAsRefs", "Extract common parameters as refs at specification level"
+ );
+ private Option combineCommonParametersInSamePathOption = makeVisibleFlagOption(
+ "combineCommonParametersInSamePath", "Combine common parameters in same path"
+ );
public GetOpenApiDocAction() {
this(NAME, true);
@@ -60,13 +78,61 @@ public GetOpenApiDocAction() {
protected GetOpenApiDocAction(String alias, boolean displayHelp) {
super(alias);
setOptions(
- Arrays.asList(classPathOption, outputOption, warOption, hostnameOption, basePathOption));
+ Arrays.asList(classPathOption, outputOption, warOption, hostnameOption, basePathOption,
+ titleOption, descriptionOption, apiNameOption,
+ tagTemplateOption, operationIdTemplateOption,
+ addGoogleJsonErrorAsDefaultResponseOption, addErrorCodesForServiceExceptionsOption,
+ extractCommonParametersAsRefsOption, combineCommonParametersInSamePathOption));
setShortDescription("Generates an OpenAPI document");
setExampleString(" " + getNames()[0]
+ " com.google.devrel.samples.ttt.spi.BoardV1 com.google.devrel.samples.ttt.spi.ScoresV1");
setHelpDisplayNeeded(displayHelp);
}
+ private static Option makeTitleOption() {
+ return EndpointsOption.makeVisibleNonFlagOption(
+ "t",
+ "title",
+ "TITLE",
+ "Sets the title for the generated document. Default is the app's host.");
+ }
+
+ private static Option makeDescriptionOption() {
+ return EndpointsOption.makeVisibleNonFlagOption(
+ "d",
+ "description",
+ "DESCRIPTION",
+ "Sets the description for the generated document. Is empty by default.");
+ }
+
+ private static Option makeApiNameOption() {
+ return EndpointsOption.makeVisibleNonFlagOption(
+ "a",
+ "apiName",
+ "API_NAME",
+ "Sets the api name. Endpoints Management will use hostname if not defined.");
+ }
+
+ private static Option makeTagTemplateOption() {
+ return EndpointsOption.makeVisibleNonFlagOption(
+ "tt",
+ "tagTemplate",
+ "TAG_TEMPLATE",
+ "Sets the tag template name. Defaults to " + SwaggerContext.DEFAULT_TAG_TEMPLATE + ".");
+ }
+
+ private static Option makeOperationIdTemplateOption() {
+ return EndpointsOption.makeVisibleNonFlagOption(
+ "oit",
+ "operationIdTemplate",
+ "OPERATION_ID_TEMPLATE",
+ "Sets the operation id template. Defaults to " + SwaggerContext.DEFAULT_OPERATION_ID_TEMPLATE + ".");
+ }
+
+ private static boolean getBooleanOptionValue(Option option) {
+ return option.getValue() != null;
+ }
+
@Override
public String getUsageString() {
return getNames()[0] + " ...";
@@ -81,7 +147,17 @@ public boolean execute() throws ClassNotFoundException, IOException, ApiConfigEx
}
genOpenApiDoc(computeClassPath(warPath, getClassPath(classPathOption)),
getOpenApiOutputPath(outputOption), getHostname(hostnameOption, warPath),
- getBasePath(basePathOption), serviceClassNames, true);
+ getBasePath(basePathOption),
+ getOptionOrDefault(titleOption, null),
+ getOptionOrDefault(descriptionOption, null),
+ getOptionOrDefault(apiNameOption, null),
+ getOptionOrDefault(tagTemplateOption, SwaggerContext.DEFAULT_TAG_TEMPLATE),
+ getOptionOrDefault(operationIdTemplateOption, SwaggerContext.DEFAULT_OPERATION_ID_TEMPLATE),
+ getBooleanOptionValue(addGoogleJsonErrorAsDefaultResponseOption),
+ getBooleanOptionValue(addErrorCodesForServiceExceptionsOption),
+ getBooleanOptionValue(extractCommonParametersAsRefsOption),
+ getBooleanOptionValue(combineCommonParametersInSamePathOption),
+ serviceClassNames, true);
return true;
}
@@ -98,6 +174,10 @@ public boolean execute() throws ClassNotFoundException, IOException, ApiConfigEx
*/
public String genOpenApiDoc(
URL[] classPath, String outputFilePath, String hostname, String basePath,
+ String title, String description, String apiName,
+ String tagTemplate, String operationIdTemplate,
+ boolean addGoogleJsonErrorAsDefaultResponse, boolean addErrorCodesForServiceExceptionsOption,
+ boolean extractCommonParametersAsRefsOption, boolean combineCommonParametersInSamePathOption,
List serviceClassNames, boolean outputToDisk)
throws ClassNotFoundException, IOException, ApiConfigException {
File outputFile = new File(outputFilePath);
@@ -120,12 +200,21 @@ public String genOpenApiDoc(
SwaggerGenerator generator = new SwaggerGenerator();
SwaggerContext swaggerContext = new SwaggerContext()
.setHostname(hostname)
- .setBasePath(basePath);
- Swagger swagger = generator.writeSwagger(apiConfigs, true, swaggerContext);
+ .setBasePath(basePath)
+ .setTitle(title)
+ .setDescription(description)
+ .setApiName(apiName)
+ .setTagTemplate(tagTemplate)
+ .setOperationIdTemplate(operationIdTemplate)
+ .setAddGoogleJsonErrorAsDefaultResponse(addGoogleJsonErrorAsDefaultResponse)
+ .setAddErrorCodesForServiceExceptions(addErrorCodesForServiceExceptionsOption)
+ .setExtractCommonParametersAsRefs(extractCommonParametersAsRefsOption)
+ .setCombineCommonParametersInSamePath(combineCommonParametersInSamePathOption);
+ Swagger swagger = generator.writeSwagger(apiConfigs, swaggerContext);
String swaggerStr = Json.mapper().writer(new EndpointsPrettyPrinter())
.writeValueAsString(swagger);
if (outputToDisk) {
- Files.write(swaggerStr, outputFile, UTF_8);
+ Files.asCharSink(outputFile, UTF_8).write(swaggerStr);
System.out.println("OpenAPI document written to " + outputFilePath);
}
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/JacksonUtil.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/JacksonUtil.java
index 14788742..b15a46f4 100644
--- a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/JacksonUtil.java
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/JacksonUtil.java
@@ -47,7 +47,7 @@ public static ObjectNode mergeObject(ObjectNode object1, ObjectNode object2,
JsonNode child2 = object2.get(fieldName);
JsonNode child1 = object1.get(fieldName);
JsonNode merged = (child1 == null) ? child2 : mergeNode(child1, child2, throwOnConflict);
- object1.put(fieldName, merged);
+ object1.set(fieldName, merged);
}
return object1;
}
diff --git a/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/LocalClientLibGenerator.java b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/LocalClientLibGenerator.java
new file mode 100644
index 00000000..b09834ea
--- /dev/null
+++ b/endpoints-framework-tools/src/main/java/com/google/api/server/spi/tools/LocalClientLibGenerator.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static java.lang.System.getProperty;
+import static java.lang.System.getenv;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.input.ReaderInputStream;
+
+import com.google.api.server.spi.IoUtil;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.CharSource;
+
+/**
+ * Implementation of (@link ClientLibGenerator} using a local tool for generation.
+ * The Python package google-apis-client-generator must be installed:
+ *
+ */
+public class LocalClientLibGenerator implements ClientLibGenerator {
+
+ private static final Logger log = Logger.getLogger(LocalClientLibGenerator.class.getName());
+
+ @VisibleForTesting
+ static final String GENERATOR_EXECUTABLE = "generate_library";
+ private static final String GENERATOR_DISCOVERY_FILE_OPTION = "--input=";
+ private static final String GENERATOR_LANGUAGE_OPTION = "--language=";
+ private static final String GENERATOR_DESTINATION_DIRECTORY_OPTION = "--output_dir=";
+ /* Put API version in package paths. */
+ private static final String GENERATOR_API_VERSION_PACKAGE_OPTION = "--version_package";
+
+ private static final List GENERATOR_SUPPORTED_LANGUAGES = ImmutableList.of("java");
+
+ /**
+ * Generate the source code.
+ * @param discoveryDoc Discovery document of the API
+ * @param language Only java is supported.
+ * @param languageVersion Ignored.
+ * @param layout Ignored.
+ * @param destinationDirectory Target directory to generate source code into.
+ * @throws IOException on failure
+ */
+ @Override
+ public void generateClientLib(String discoveryDoc, String language, String languageVersion,
+ String layout, File destinationDirectory) throws IOException {
+ Preconditions.checkArgument(GENERATOR_SUPPORTED_LANGUAGES.contains(language), "Unsupported language: " + language);
+
+ // Creates the destination directory
+ Files.createDirectories(destinationDirectory.toPath());
+
+ // Creates a temporary discovery file
+ File discoveryFile = File.createTempFile(GENERATOR_EXECUTABLE, "-discovery.tmp");
+ try {
+ IoUtil.copy(new ReaderInputStream(CharSource.wrap(discoveryDoc).openStream()), discoveryFile);
+
+ File generateLibOut = File.createTempFile(GENERATOR_EXECUTABLE, ".out");
+ File generateLibErr = File.createTempFile(GENERATOR_EXECUTABLE, ".err");
+
+ List command = new ArrayList<>(getLibraryGeneratorCommand());
+ command.add(GENERATOR_DISCOVERY_FILE_OPTION + discoveryFile);
+ command.add(GENERATOR_LANGUAGE_OPTION + language);
+ command.add(GENERATOR_DESTINATION_DIRECTORY_OPTION + destinationDirectory.getAbsolutePath());
+ command.add(GENERATOR_API_VERSION_PACKAGE_OPTION);
+
+ ProcessBuilder builder = new ProcessBuilder()
+ .command(command)
+ .redirectOutput(generateLibOut)
+ .redirectError(generateLibErr);
+ int status;
+ try {
+ status = builder.start().waitFor();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Source code generation interrupted", e);
+ }
+ if (status == 0) {
+ // Success: get rid of output files
+ generateLibOut.delete();
+ generateLibErr.delete();
+ } else {
+ throw new IOException("Failed to generate source code. See " + generateLibErr.getAbsolutePath() + " for details");
+ }
+ } finally {
+ discoveryFile.delete();
+ }
+ }
+
+ private List getLibraryGeneratorCommand() {
+ if (getProperty("os.name").toLowerCase().contains("win")) {
+ log.warning("You are using the LocalClientLibGenerator on Windows.\n"
+ + "You should specify the following environmental variables:\n"
+ + "- GOOGLE_GENERATE_LIBRARY_PYTHON to point at your Python 2.7 installation\n"
+ + "- GOOGLE_GENERATE_LIBRARY_SCRIPT_LOCATION to point at the location where your generate_library.py script was installed (it should be something like 'C:\\Users\\Armin\\AppData\\Roaming\\Python\\Python27\\site-packages\\googleapis\\codegen\\generate_library.py')");
+
+ // The generate_library.exe runs library generation asynchronously on Windows due to https://bugs.python.org/issue9148
+ // so we call the script directly
+
+ String python = firstNonNull(
+ getenv("GOOGLE_GENERATE_LIBRARY_PYTHON"),
+ "python"
+ );
+
+ String scriptLocation = firstNonNull(
+ getenv("GOOGLE_GENERATE_LIBRARY_SCRIPT_LOCATION"),
+ getProperty("user.home") + "\\AppData\\Roaming\\Python\\Python27\\site-packages\\googleapis\\codegen\\generate_library.py"
+ );
+
+ File scriptLocationFile = new File(scriptLocation);
+ Preconditions.checkArgument(scriptLocation.endsWith("generate_library.py"), "You should specify a generate_library.py in the GOOGLE_GENERATE_LIBRARY_SCRIPT_LOCATION env var");
+ Preconditions.checkArgument(scriptLocationFile.isFile(), "Could not find script at '" + scriptLocationFile.getAbsolutePath() + "': make the GOOGLE_GENERATE_LIBRARY_SCRIPT_LOCATION env var point at the generate_library.py script you have installed");
+
+ return Arrays.asList(python, scriptLocationFile.getAbsolutePath());
+ }
+
+ return Collections.singletonList(GENERATOR_EXECUTABLE);
+ }
+}
diff --git a/endpoints-framework-tools/src/main/resources/com/google/api/server/spi/tools/testing/fake-discovery-doc-rest.json b/endpoints-framework-tools/src/main/resources/com/google/api/server/spi/tools/testing/fake-discovery-doc-rest.json
index 3bd712c6..ce531cb3 100644
--- a/endpoints-framework-tools/src/main/resources/com/google/api/server/spi/tools/testing/fake-discovery-doc-rest.json
+++ b/endpoints-framework-tools/src/main/resources/com/google/api/server/spi/tools/testing/fake-discovery-doc-rest.json
@@ -3,6 +3,9 @@
"id": "guestbook:v1",
"name": "guestbook",
"version": "v1",
+ "ownerDomain": "google.com",
+ "ownerName": "Google",
+ "packagePath": "client",
"description": "App Engine GuestBook API",
"icons": {
"x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png",
diff --git a/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GenClientSrcActionTest.java b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GenClientSrcActionTest.java
new file mode 100644
index 00000000..8c416d62
--- /dev/null
+++ b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GenClientSrcActionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link GenClientSrcAction}.
+ */
+@RunWith(JUnit4.class)
+public class GenClientSrcActionTest extends EndpointsToolTest {
+
+ private String language;
+ private String outputDirPath;
+ private String discoveryDocPath;
+
+ @Override
+ protected void addTestAction(Map commands) {
+ commands.put(GenClientSrcAction.NAME, new GenClientSrcAction() {
+
+ @Override
+ public Object genClientSrcFromFile(String l, String o, String d) {
+ language = l;
+ outputDirPath = o;
+ discoveryDocPath = d;
+ return null;
+ }
+ });
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ usagePrinted = false;
+ language = null;
+ outputDirPath = null;
+ discoveryDocPath = null;
+ }
+
+ @Test
+ public void testGenClientSrc() throws Exception {
+ tool.execute(
+ new String[]{GenClientSrcAction.NAME, option(EndpointsToolAction.OPTION_LANGUAGE_SHORT),
+ "java", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir",
+ "discoveryDocPath"});
+ assertFalse(usagePrinted);
+ assertEquals("java", language);
+ assertEquals("outputDir", outputDirPath);
+ assertEquals("discoveryDocPath", discoveryDocPath);
+ }
+}
diff --git a/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetClientSrcActionTest.java b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetClientSrcActionTest.java
new file mode 100644
index 00000000..d6654855
--- /dev/null
+++ b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetClientSrcActionTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.util.Collections.singletonList;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Tests for {@link GetClientSrcAction}.
+ */
+@RunWith(JUnit4.class)
+public class GetClientSrcActionTest extends EndpointsToolTest {
+
+ private URL[] classPath;
+ private String language;
+ private String outputDirPath;
+ private List serviceClassNames;
+ private boolean debugOutput;
+ private String hostname;
+ private String basePath;
+ private GetClientSrcAction testAction;
+
+ @Override
+ protected void addTestAction(Map commands) {
+ commands.put(GetClientSrcAction.NAME, testAction);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ usagePrinted = false;
+ classPath = null;
+ language = null;
+ outputDirPath = null;
+ serviceClassNames = null;
+ hostname = null;
+ basePath = null;
+ testAction = new GetClientSrcAction() {
+
+ @Override
+ public Object getClientSrc(
+ URL[] c, String l, String o, List s, String h, String bp, boolean d) {
+ classPath = c;
+ language = l;
+ outputDirPath = o;
+ serviceClassNames = s;
+ hostname = h;
+ basePath = bp;
+ debugOutput = d;
+ return null;
+ }
+ };
+ }
+
+ @Test
+ public void testMissingOption() throws Exception {
+ tool.execute(new String[]{GetClientSrcAction.NAME,
+ option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT), "classPath",
+ option(EndpointsToolAction.OPTION_HOSTNAME_SHORT), "foo.com",
+ "MyService"});
+ assertFalse(usagePrinted);
+ assertThat(Lists.newArrayList(classPath))
+ .containsExactly(new File("classPath").toURI().toURL(),
+ new File(new File(EndpointsToolAction.DEFAULT_WAR_PATH).getAbsoluteFile(),
+ "/WEB-INF/classes")
+ .toURI()
+ .toURL());
+ assertEquals(EndpointsToolAction.DEFAULT_LANGUAGE, language);
+ assertEquals(EndpointsToolAction.DEFAULT_OUTPUT_PATH, outputDirPath);
+ assertStringsEqual(singletonList("MyService"), serviceClassNames);
+ }
+
+ @Test
+ public void testMissingArgument() throws Exception {
+ tool.execute(new String[]{
+ GetClientSrcAction.NAME, option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT),
+ "classPath", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir"});
+ assertTrue(usagePrinted);
+ }
+
+ @Test
+ public void testGetClientSrc() throws Exception {
+ tool.execute(new String[]{GetClientSrcAction.NAME,
+ option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT), "classPath",
+ option(EndpointsToolAction.OPTION_LANGUAGE_SHORT), "java",
+ option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir",
+ option(EndpointsToolAction.OPTION_HOSTNAME_SHORT), "foo.com",
+ "MyService", "MyService2"});
+ assertFalse(usagePrinted);
+ assertThat(Lists.newArrayList(classPath))
+ .containsExactly(new File("classPath").toURI().toURL(),
+ new File(new File(EndpointsToolAction.DEFAULT_WAR_PATH).getAbsoluteFile(),
+ "/WEB-INF/classes")
+ .toURI()
+ .toURL());
+ assertEquals("java", language);
+ assertEquals("outputDir", outputDirPath);
+ assertStringsEqual(Arrays.asList("MyService", "MyService2"), serviceClassNames);
+ assertFalse(debugOutput);
+ assertThat(basePath).isEqualTo("/_ah/api");
+ }
+
+ @Test
+ public void testGetClientSrcWithDebugOutput() throws Exception {
+ tool.execute(new String[]{GetClientSrcAction.NAME,
+ option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT), "classPath",
+ option(EndpointsToolAction.OPTION_LANGUAGE_SHORT), "java",
+ option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir",
+ option(EndpointsToolAction.OPTION_DEBUG, false),
+ option(EndpointsToolAction.OPTION_HOSTNAME_SHORT), "foo.com",
+ option(EndpointsToolAction.OPTION_BASE_PATH_SHORT), "/api",
+ "MyService", "MyService2"});
+ assertFalse(usagePrinted);
+ assertThat(Lists.newArrayList(classPath))
+ .containsExactly(new File("classPath").toURI().toURL(),
+ new File(new File(EndpointsToolAction.DEFAULT_WAR_PATH).getAbsoluteFile(),
+ "/WEB-INF/classes")
+ .toURI()
+ .toURL());
+ assertEquals("java", language);
+ assertEquals("outputDir", outputDirPath);
+ assertStringsEqual(Arrays.asList("MyService", "MyService2"), serviceClassNames);
+ assertTrue(debugOutput);
+ assertThat(hostname).isEqualTo("foo.com");
+ assertThat(basePath).isEqualTo("/api");
+ }
+}
diff --git a/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetOpenApiDocActionTest.java b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetOpenApiDocActionTest.java
index aa37e6b1..f4692c15 100644
--- a/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetOpenApiDocActionTest.java
+++ b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/GetOpenApiDocActionTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.google.api.server.spi.swagger.SwaggerGenerator.SwaggerContext;
import com.google.appengine.tools.util.Option;
import com.google.common.collect.Lists;
@@ -44,7 +45,11 @@ public class GetOpenApiDocActionTest extends EndpointsToolTest {
private String outputFilePath;
private String basePath;
private List serviceClassNames;
+ private String tagTemplate;
+ private String operationIdTemplate;
private boolean outputToDisk;
+ private boolean addGoogleJsonErrorAsDefaultResponse;
+ private boolean addErrorCodesForServiceExceptionsOption;
@Override
protected void addTestAction(Map actions) {
@@ -53,12 +58,24 @@ protected void addTestAction(Map actions) {
@Override
public String genOpenApiDoc(
URL[] classPath, String outputFilePath, String hostname, String basePath,
+ String title, String description, String apiName,
+ String tagTemplate, String operationIdTemplate,
+ boolean addGoogleJsonErrorAsDefaultResponse,
+ boolean addErrorCodesForServiceExceptionsOption,
+ boolean extractCommonParametersAsRefsOption,
+ boolean combineCommonParametersInSamePathOption,
List serviceClassNames, boolean outputToDisk) {
GetOpenApiDocActionTest.this.classPath = classPath;
GetOpenApiDocActionTest.this.outputFilePath = outputFilePath;
GetOpenApiDocActionTest.this.basePath = basePath;
GetOpenApiDocActionTest.this.serviceClassNames = serviceClassNames;
+ GetOpenApiDocActionTest.this.tagTemplate = tagTemplate;
+ GetOpenApiDocActionTest.this.operationIdTemplate = operationIdTemplate;
GetOpenApiDocActionTest.this.outputToDisk = outputToDisk;
+ GetOpenApiDocActionTest.this.addGoogleJsonErrorAsDefaultResponse
+ = addGoogleJsonErrorAsDefaultResponse;
+ GetOpenApiDocActionTest.this.addErrorCodesForServiceExceptionsOption
+ = addErrorCodesForServiceExceptionsOption;
return null;
}
@@ -84,7 +101,10 @@ public void setUp() throws Exception {
public void testGetOpenApiDoc() throws Exception {
tool.execute(
new String[]{GetOpenApiDocAction.NAME, option(EndpointsToolAction.OPTION_CLASS_PATH_SHORT),
- "classPath", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir", "MyService",
+ "classPath", option(EndpointsToolAction.OPTION_OUTPUT_DIR_SHORT), "outputDir",
+ option("addGoogleJsonErrorAsDefaultResponse", false),
+ option("tt"), "myCustomTemplate",
+ "MyService",
"MyService2"});
assertFalse(usagePrinted);
assertThat(Lists.newArrayList(classPath))
@@ -95,6 +115,10 @@ public void testGetOpenApiDoc() throws Exception {
.toURL());
assertEquals("outputDir", outputFilePath);
assertEquals(EndpointsToolAction.DEFAULT_BASE_PATH, basePath);
+ assertTrue(addGoogleJsonErrorAsDefaultResponse);
+ assertFalse(addErrorCodesForServiceExceptionsOption);
+ assertEquals("myCustomTemplate", tagTemplate);
+ assertEquals(SwaggerContext.DEFAULT_OPERATION_ID_TEMPLATE, operationIdTemplate);
assertStringsEqual(Arrays.asList("MyService", "MyService2"), serviceClassNames);
assertTrue(outputToDisk);
}
diff --git a/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/LocalClientLibGeneratorTest.java b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/LocalClientLibGeneratorTest.java
new file mode 100644
index 00000000..d59de336
--- /dev/null
+++ b/endpoints-framework-tools/src/test/java/com/google/api/server/spi/tools/LocalClientLibGeneratorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.api.server.spi.tools;
+
+import static org.junit.Assume.assumeTrue;
+
+import static com.google.api.server.spi.tools.LocalClientLibGenerator.GENERATOR_EXECUTABLE;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.google.api.server.spi.IoUtil;
+import com.google.api.server.spi.tools.testing.FakeClientLibGenerator;
+
+public class LocalClientLibGeneratorTest {
+
+ @Rule
+ public TemporaryFolder tmpFolder = new TemporaryFolder();
+
+ private LocalClientLibGenerator generator;
+ private String discoveryDoc;
+
+ @Before
+ public void init() throws Exception {
+ generator = new LocalClientLibGenerator();
+ discoveryDoc = IoUtil.readStream(FakeClientLibGenerator.class.getResourceAsStream("fake-discovery-doc-rest.json"));
+ }
+
+ @Test
+ public void testJavaCodeGeneration() throws Exception {
+ assumeTrue(isToolInstalled());
+
+ File destinationDir = tmpFolder.newFolder("destination");
+ generator.generateClientLib(discoveryDoc, "java", null, null, destinationDir);
+ File com = new File(destinationDir, "com");
+ Assert.assertTrue(com.isDirectory());
+ File google = new File(com, "google");
+ Assert.assertTrue(google.isDirectory());
+ File client = new File(google, "client");
+ Assert.assertTrue(client.isDirectory());
+ File guestbook = new File(client, "guestbook");
+ Assert.assertTrue(guestbook.isDirectory());
+ File v1 = new File(guestbook, "v1");
+ Assert.assertTrue(guestbook.isDirectory());
+ File model = new File(v1, "model");
+ Assert.assertTrue(model.isDirectory());
+ File guestbookJava = new File(v1, "Guestbook.java");
+ Assert.assertTrue(guestbookJava.isFile());
+ File guestbookRequestJava = new File(v1, "GuestbookRequest.java");
+ Assert.assertTrue(guestbookRequestJava.isFile());
+ File guestbookRequestInitializerJava = new File(v1, "GuestbookRequestInitializer.java");
+ Assert.assertTrue(guestbookRequestInitializerJava.isFile());
+ File greetingJava = new File(model, "Greeting.java");
+ Assert.assertTrue(greetingJava.isFile());
+ }
+
+ @Test
+ public void testDestinationDirectoryCreation() throws Exception {
+ assumeTrue(isToolInstalled());
+
+ File destinationParent = tmpFolder.newFolder("destination");
+ File dir1 = new File(destinationParent, "d1");
+ File destinationDir = new File(dir1, "d2");
+ Assert.assertFalse(dir1.exists());
+ Assert.assertFalse(destinationDir.exists());
+ generator.generateClientLib(discoveryDoc, "java", null, null, destinationDir);
+ Assert.assertTrue(dir1.exists());
+ Assert.assertTrue(destinationDir.exists());
+ }
+
+ @Test
+ public void testInvalidDiscoveryFile_fails() throws Exception {
+ assumeTrue(isToolInstalled());
+
+ discoveryDoc = IoUtil.readStream(FakeClientLibGenerator.class.getResourceAsStream("fake-api-config.json"));
+ File destinationDir = tmpFolder.newFolder("destination");
+ Assert.assertThrows(IOException.class, () ->
+ generator.generateClientLib(discoveryDoc, "java", null, null, destinationDir)
+ );
+ }
+
+ @Test
+ public void testDestinationIsFile_fails() throws Exception {
+ assumeTrue(isToolInstalled());
+
+ File destinationFile = tmpFolder.newFile("destination");
+ Assert.assertThrows(IOException.class, () ->
+ generator.generateClientLib(discoveryDoc, "java", null, null, destinationFile)
+ );
+ }
+
+ @Test
+ public void testLanguageUnsupported() throws Exception {
+ assumeTrue(isToolInstalled());
+
+ IllegalArgumentException e = Assert.assertThrows(IllegalArgumentException.class, () ->
+ generator.generateClientLib(discoveryDoc, "python", null, null, tmpFolder.getRoot())
+ );
+ Assert.assertEquals("Unsupported language: python", e.getMessage());
+ }
+
+ /**
+ * Checks if the generator is installed.
+ */
+ private boolean isToolInstalled() {
+ try {
+ Runtime.getRuntime().exec(GENERATOR_EXECUTABLE);
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+}
diff --git a/endpoints-framework/build.gradle b/endpoints-framework/build.gradle
index 1645cea6..932197f1 100644
--- a/endpoints-framework/build.gradle
+++ b/endpoints-framework/build.gradle
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
plugins {
- id 'net.ltgt.apt' version '0.8'
+ id 'java-library'
}
configurations {
include
- compile.extendsFrom include
+ compileOnly.extendsFrom include
}
jar {
@@ -47,7 +46,6 @@ def annotations = [
"ApiTransformer.java",
"Authenticator.java",
"DefaultValue.java",
- "PeerAuthenticator.java",
"AuthLevel.java",
"Transformer.java",
]
@@ -73,47 +71,55 @@ task copyTestResources(type: Copy) {
processTestResources.dependsOn copyTestResources
dependencies {
- include(project(":discovery-client")) {
+ include(project(":discovery-client")) {
// We already include all of the dependencies needed for the discovery
// client, and they are often newer versions. Leaving this out can cause
// Android Studio to confuse different versions of Jackson 2 and Guava,
// leading to test failures.
transitive = false
}
- compile group: 'com.google.guava', name: 'guava', version: guavaVersion
- compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion
- compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion
- compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion
- compile group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: appengineVersion
- compile group: 'com.google.flogger', name: 'flogger', version: floggerVersion
- runtime group: 'com.google.flogger', name: 'flogger-system-backend', version: floggerVersion
- compile(group: 'com.google.http-client', name: 'google-http-client-jackson2', version: apiclientVersion) {
- exclude group: 'com.google.guava', module: 'guava-jdk5'
+ api (group: 'com.google.guava', name: 'guava', version: guavaVersion) { force = true }
+ api (group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion)
+ api (group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: jacksonVersion)
+ api (group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion)
+ api group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: jacksonVersion
+ api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: jacksonVersion
+ api group: 'com.google.appengine', name: 'appengine-api-1.0-sdk', version: appengineVersion
+ api group: 'com.google.flogger', name: 'flogger', version: floggerVersion
+ implementation group: 'com.google.flogger', name: 'flogger-system-backend', version: floggerVersion
+ api(group: 'com.google.http-client', name: 'google-http-client-jackson2', version: httpClientVersion) {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core'
}
- compile(group: 'com.google.api-client', name: 'google-api-client', version: apiclientVersion) {
- exclude group: 'com.google.guava', module: 'guava-jdk5'
- }
- compile(group: 'com.google.api-client', name: 'google-api-client-appengine', version: apiclientVersion) {
- exclude group: 'com.google.guava', module: 'guava-jdk5'
+ api(group: 'com.google.api-client', name: 'google-api-client', version: apiclientVersion)
+ api(group: 'com.google.api-client', name: 'google-api-client-appengine', version: apiclientVersion)
+ compileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: findbugsVersion
+ api group: 'commons-fileupload', name: 'commons-fileupload', version: fileUploadVersion
+ api group: 'io.swagger', name: 'swagger-models', version: swaggerVersion
+ api(group: 'io.swagger', name: 'swagger-core', version: swaggerVersion) {
+ exclude group: 'javax.validation', module: 'validation-api'
}
- compile group: 'com.google.code.findbugs', name: 'jsr305', version: findbugsVersion
- compile group: 'commons-fileupload', name: 'commons-fileupload', version: fileUploadVersion
- compile group: 'io.swagger', name: 'swagger-models', version: swaggerVersion
- compile group: 'io.swagger', name: 'swagger-core', version: swaggerVersion
- compile group: 'org.slf4j', name: 'slf4j-nop', version: slf4jVersion
+ compileOnly group: 'org.slf4j', name: 'slf4j-nop', version: slf4jVersion
compileOnly group: 'javax.servlet', name: 'servlet-api', version: servletVersion
- compileOnly "com.google.auto.value:auto-value:1.2"
- apt "com.google.auto.value:auto-value:1.2"
+ compileOnly group: 'com.google.auto.value', name: 'auto-value-annotations', version: autoValueVersion
+ annotationProcessor group: 'com.google.auto.value', name: 'auto-value', version: autoValueVersion
- testCompile project(':test-utils')
- testCompile group: 'junit', name: 'junit', version: junitVersion
- testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
- testCompile group: 'com.google.truth', name: 'truth', version: truthVersion
- testCompile group: 'com.google.appengine', name: 'appengine-testing', version: appengineVersion
- testCompile group: 'com.google.appengine', name: 'appengine-api-stubs', version: appengineVersion
- testCompile group: 'org.springframework', name: 'spring-test', version: springtestVersion
- testCompile group: 'com.google.guava', name: 'guava-testlib', version: guavaVersion
-}
+ api group: 'org.hibernate.validator', name: 'hibernate-validator', version: hibernateValidatorVersion
+ api group: 'jakarta.validation', name: 'jakarta.validation-api', version: validationApiVersion
+ testImplementation project(':test-utils')
+ testImplementation project(':discovery-client')
+ testImplementation group: 'junit', name: 'junit', version: junitVersion
+ testImplementation group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
+ testImplementation group: 'org.skyscreamer', name: 'jsonassert', version: jsonassertVersion
+ testImplementation group: 'com.google.truth', name: 'truth', version: truthVersion
+ testImplementation group: 'com.google.appengine', name: 'appengine-testing', version: appengineVersion
+ testImplementation group: 'com.google.appengine', name: 'appengine-api-stubs', version: appengineVersion
+ testImplementation group: 'org.springframework', name: 'spring-test', version: springtestVersion
+ testImplementation group: 'com.google.guava', name: 'guava-testlib', version: guavaVersion
+ testImplementation (group: 'io.swagger', name: 'swagger-validator', version: '1.0.7') {
+ exclude group: 'javax.servlet', module: 'javax.servlet-api'
+ exclude group: 'javax.validation', module: 'validation-api'
+ exclude group: 'ch.qos.logback', module: 'logback-classic'
+ }
+}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/ConfiguredObjectMapper.java b/endpoints-framework/src/main/java/com/google/api/server/spi/ConfiguredObjectMapper.java
index 03db8af8..df3a1ec5 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/ConfiguredObjectMapper.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/ConfiguredObjectMapper.java
@@ -20,21 +20,23 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import com.google.common.flogger.FluentLogger;
-import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonInclude.Value;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
-import com.fasterxml.jackson.databind.SerializationFeature;
+import javax.annotation.Nullable;
-import com.google.common.flogger.FluentLogger;
import java.util.Map;
import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.annotation.Nullable;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.stream.Stream;
/**
* A wrapper around an {@link ObjectMapper} with a frozen configuration. This exposes a subset of
@@ -137,6 +139,7 @@ public Builder addRegisteredModules(Iterable extends Module> modules) {
/**
* Builds a {@link ConfiguredObjectMapper} using the configuration specified in this builder.
+ * Returns a cached instance unsing {@link ApiSerializationConfig} and modules as key.
*
* @return the constructed object
*/
@@ -146,8 +149,16 @@ public ConfiguredObjectMapper build() {
if (instance == null) {
ObjectMapper mapper =
ObjectMapperUtil.createStandardObjectMapper(key.apiSerializationConfig);
- mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- mapper.disable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS);
+ mapper.setDefaultPropertyInclusion(Include.NON_EMPTY);
+ Stream.of(
+ //empty Strings must be serialized
+ String.class,
+ //Empty optionals should serialized by default
+ Optional.class, OptionalLong.class, OptionalDouble.class, OptionalInt.class)
+ .forEach(clazz -> mapper.configOverride(clazz)
+ .setIncludeAsProperty(Value.construct(Include.NON_NULL, Include.USE_DEFAULTS)));
+ mapper.configOverride(Map.class)
+ .setIncludeAsProperty(Value.construct(Include.USE_DEFAULTS, Include.NON_NULL));
for (Module module : key.modulesSet) {
mapper.registerModule(module);
}
@@ -165,6 +176,20 @@ public ConfiguredObjectMapper build() {
}
return instance;
}
+
+ /**
+ * Builds a {@link ConfiguredObjectMapper} using the configuration specified in this builder,
+ * and a customized ObjectMapper instance. Returned instance is NOT cached.
+ *
+ * @param mapper low-level Jackson {@link ObjectMapper}
+ * @return the constructed object
+ */
+ public ConfiguredObjectMapper buildWithCustomMapper(ObjectMapper mapper) {
+ for (Module module : modules.build()) {
+ mapper.registerModule(module);
+ }
+ return new ConfiguredObjectMapper(mapper);
+ }
}
// A key that uniquely identify a cached object mapper.
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/Constant.java b/endpoints-framework/src/main/java/com/google/api/server/spi/Constant.java
index 75c9d076..3c77cbb9 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/Constant.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/Constant.java
@@ -55,18 +55,23 @@ private Constant() {}
public static final String SKIP_CLIENT_ID_CHECK = "*";
/**
- * Root URL of discovery doc generation API. This is on a host that Endpoints project owns so
- * that even if producer has not picked an App Engine app host, this call can still succeed.
+ * Friendly name to refer to Google ID token authentication with accounts.google.com issuer.
*/
- public static final String DISCOVERY_GEN_ROOT = "https://webapis-discovery.appspot.com/_ah/api";
+ public static final String GOOGLE_ID_TOKEN_ALT = "google_id_token_legacy";
/**
- * Friendly name to refer to Google ID token authentication with accounts.google.com issuer.
+ * Google ID token authentication variant with https://accounts.google.com issuer.
*/
public static final String GOOGLE_ID_TOKEN_NAME = "google_id_token";
/**
- * Google ID token authentication variant with https://accounts.google.com issuer.
+ * Google JWKS URI
+ */
+ public static final String GOOGLE_JWKS_URI = "https://www.googleapis.com/oauth2/v1/certs";
+
+ /**
+ * Google OAuth2 authentication URL
*/
- public static final String GOOGLE_ID_TOKEN_NAME_HTTPS = "google_id_token_https";
+ public static final String GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
+
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/EndpointsServlet.java b/endpoints-framework/src/main/java/com/google/api/server/spi/EndpointsServlet.java
index 5f32bc6c..0c04d84e 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/EndpointsServlet.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/EndpointsServlet.java
@@ -117,7 +117,8 @@ private PathDispatcher createDispatcher() {
builder.add(handler.getRestMethod(), Strings.stripTrailingSlash(handler.getRestPath()),
handler.getRestHandler());
}
- ExplorerHandler explorerHandler = new ExplorerHandler();
+ String apiExplorerUrlTemplate = initParameters.getApiExplorerUrlTemplate();
+ ExplorerHandler explorerHandler = new ExplorerHandler(apiExplorerUrlTemplate);
builder.add("GET", EXPLORER_PATH, explorerHandler);
builder.add("GET", EXPLORER_PATH + "/", explorerHandler);
builder.add("GET", "static/proxy.html", new ApiProxyHandler());
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/EnvUtil.java b/endpoints-framework/src/main/java/com/google/api/server/spi/EnvUtil.java
index 49b9c2cb..6548ffdf 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/EnvUtil.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/EnvUtil.java
@@ -21,6 +21,7 @@
*/
public class EnvUtil {
public static final String ENV_APPENGINE_RUNTIME = "com.google.appengine.runtime.environment";
+ public static final String FORCE_AUTHENTICATION_ENABLED = "com.aodocs.auth.force.enabled";
public static final String ENV_APPENGINE_PROD = "Production";
private static final String ORIGINAL_APPENGINE_RUNTIME_ENV =
System.getProperty(EnvUtil.ENV_APPENGINE_RUNTIME);
@@ -56,4 +57,11 @@ public static boolean isRunningOnAppEngineProd() {
String property = System.getProperty(ENV_APPENGINE_RUNTIME);
return property != null && property.equals(ENV_APPENGINE_PROD);
}
+
+ /**
+ * Returns whether force authentication is enabled.
+ */
+ public static boolean hasForceAuthenticationEnabled() {
+ return Boolean.parseBoolean(System.getProperty(FORCE_AUTHENTICATION_ENABLED));
+ }
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/IoUtil.java b/endpoints-framework/src/main/java/com/google/api/server/spi/IoUtil.java
index f8faa647..2862d24f 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/IoUtil.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/IoUtil.java
@@ -30,6 +30,7 @@
import java.io.PushbackInputStream;
import java.io.RandomAccessFile;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
@@ -55,7 +56,7 @@ private IoUtil() {}
public static String readResourceFile(Class> c, String fileName) throws IOException {
URL url = c.getResource(fileName);
StringBuilder sb = new StringBuilder();
- BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
+ BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
for (String line = in.readLine(); line != null; line = in.readLine()) {
sb.append(line);
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/MethodHierarchyReader.java b/endpoints-framework/src/main/java/com/google/api/server/spi/MethodHierarchyReader.java
index 4f909e0d..1f551157 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/MethodHierarchyReader.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/MethodHierarchyReader.java
@@ -15,16 +15,20 @@
*/
package com.google.api.server.spi;
+import com.google.api.server.spi.EndpointMethod.ResolvedSignature;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -42,7 +46,7 @@ public class MethodHierarchyReader {
private final Class> endpointClass;
// Map from method signatures to a list of method overrides for that signature (ordered
// subclass -> superclass).
- private ListMultimap endpointMethods;
+ private Multimap endpointMethods;
/**
* Constructs a {@code MethodHierarchyReader} for the given class type.
@@ -60,8 +64,8 @@ public MethodHierarchyReader(Class> endpointClass) {
private void readMethodHierarchyIfNecessary() {
if (endpointMethods == null) {
- ImmutableListMultimap.Builder builder =
- ImmutableListMultimap.builder();
+ ImmutableMultimap.Builder builder =
+ ImmutableMultimap.builder();
buildServiceMethods(builder, TypeToken.of(endpointClass));
endpointMethods = builder.build();
}
@@ -72,24 +76,10 @@ private void readMethodHierarchyIfNecessary() {
*
* @param overrides A list of method overrides ordered subclass -> superclass.
*/
- private EndpointMethod getLeafMethod(List overrides) {
+ private EndpointMethod getLeafMethod(Collection overrides) {
// Because the list is ordered subclass -> superclass, index 0 will always contain the leaf
// subclass implementation.
- return overrides.get(0);
- }
-
- /**
- * Returns {@link ListMultimap#asMap multimap.asMap()}, with its type
- * corrected from {@code Map>} to {@code Map>}.
- */
- // Copied from com.google.common.collect.Multimaps. We can't use the actual method from
- // that class as appengine build magic gives us an older version of guava that doesn't yet have
- // this method.
- // TODO: Switch to Multimaps.asMap() once it becomes available in appengine.
- @SuppressWarnings("unchecked")
- // safe by specification of ListMultimap.asMap()
- private static Map> asMap(ListMultimap multimap) {
- return (Map>) (Map) multimap.asMap();
+ return overrides.iterator().next();
}
/**
@@ -99,7 +89,7 @@ private static Map> asMap(ListMultimap multimap) {
public Iterable getLeafMethods() {
readMethodHierarchyIfNecessary();
ImmutableList.Builder builder = ImmutableList.builder();
- for (List overrides : asMap(endpointMethods).values()) {
+ for (Collection overrides : endpointMethods.asMap().values()) {
builder.add(getLeafMethod(overrides).getMethod());
}
return builder.build();
@@ -113,7 +103,7 @@ public Iterable getLeafMethods() {
public Iterable getLeafEndpointMethods() {
readMethodHierarchyIfNecessary();
ImmutableList.Builder builder = ImmutableList.builder();
- for (List overrides : asMap(endpointMethods).values()) {
+ for (Collection overrides : endpointMethods.asMap().values()) {
builder.add(getLeafMethod(overrides));
}
return builder.build();
@@ -127,7 +117,7 @@ public Iterable getLeafEndpointMethods() {
public Iterable> getMethodOverrides() {
readMethodHierarchyIfNecessary();
ImmutableList.Builder> builder = ImmutableList.builder();
- for (List overrides : asMap(endpointMethods).values()) {
+ for (Collection overrides : endpointMethods.asMap().values()) {
ImmutableList.Builder methodBuilder = ImmutableList.builder();
for (EndpointMethod method : overrides) {
methodBuilder.add(method.getMethod());
@@ -142,9 +132,9 @@ public Iterable> getMethodOverrides() {
* Bridge methods are ignored. For each method, all valid method implementations are included,
* ordered subclass to superclass. Methods are stored in the EndpointMethod container.
*/
- public Iterable> getEndpointOverrides() {
+ public Iterable> getEndpointOverrides() {
readMethodHierarchyIfNecessary();
- return asMap(endpointMethods).values();
+ return endpointMethods.asMap().values();
}
/**
@@ -155,7 +145,7 @@ public Iterable> getEndpointOverrides() {
public Map getNameToLeafMethodMap() {
readMethodHierarchyIfNecessary();
ImmutableMap.Builder builder = ImmutableMap.builder();
- for (List overrides : asMap(endpointMethods).values()) {
+ for (Collection overrides : endpointMethods.asMap().values()) {
Method leafMethod = getLeafMethod(overrides).getMethod();
builder.put(leafMethod.getName(), leafMethod);
}
@@ -170,7 +160,7 @@ public Map getNameToLeafMethodMap() {
public ListMultimap getNameToEndpointOverridesMap() {
readMethodHierarchyIfNecessary();
ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
- for (List overrides : asMap(endpointMethods).values()) {
+ for (Collection overrides : endpointMethods.asMap().values()) {
builder.putAll(getLeafMethod(overrides).getMethod().getName(), overrides);
}
return builder.build();
@@ -183,13 +173,14 @@ public ListMultimap getNameToEndpointOverridesMap() {
* @param serviceType is the class object being inspected for service methods
*/
private void buildServiceMethods(
- ImmutableListMultimap.Builder builder,
+ ImmutableMultimap.Builder builder,
TypeToken> serviceType) {
for (TypeToken> typeToken : serviceType.getTypes().classes()) {
Class> serviceClass = typeToken.getRawType();
if (Object.class.equals(serviceClass)) {
return;
}
+ //getDeclaredMethods returns methods in random order, so must not assume any specific order
for (Method method : serviceClass.getDeclaredMethods()) {
if (!isServiceMethod(method)) {
continue;
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/ObjectMapperUtil.java b/endpoints-framework/src/main/java/com/google/api/server/spi/ObjectMapperUtil.java
index 331dcc86..7ff6990b 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/ObjectMapperUtil.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/ObjectMapperUtil.java
@@ -17,6 +17,7 @@
import com.google.api.server.spi.config.annotationreader.ApiAnnotationIntrospector;
import com.google.api.server.spi.config.model.ApiSerializationConfig;
+import com.google.api.server.spi.config.model.EndpointsFlag;
import com.fasterxml.jackson.core.Base64Variants;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -38,8 +39,9 @@
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
-import com.google.api.server.spi.config.model.EndpointsFlag;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Collection;
@@ -66,6 +68,14 @@ public static ObjectMapper createStandardObjectMapper() {
/**
* Creates an Endpoints standard object mapper that allows unquoted field names and unknown
* properties.
+ *
+ * Some Jackson Java 8 modules (ParameterNamesModule and Jdk8Module) are enabled.
+ * They provide the following features:
+ * - Simpler support for immutable objects through automatic detection of multi-param constructors
+ * - Support for Optional, that differentiates between null value of a field (maps to
+ * Optional.empty()) and a missing fields (maps to null).
+ *
+ * Support for JSR310 has been left out for now, as it's quite complex to configure properly.
*
* Note on unknown properties: When Apiary FE supports a strict mode where properties
* are checked against the schema, BE can just ignore unknown properties. This way, FE does
@@ -87,7 +97,9 @@ public static ObjectMapper createStandardObjectMapper(ApiSerializationConfig con
new JacksonAnnotationIntrospector())
: new ApiAnnotationIntrospector(config);
objectMapper.setAnnotationIntrospector(pair);
- return objectMapper;
+ return objectMapper
+ .registerModule(new ParameterNamesModule())
+ .registerModule(new Jdk8Module());
}
/**
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/PeerAuth.java b/endpoints-framework/src/main/java/com/google/api/server/spi/PeerAuth.java
deleted file mode 100644
index 0cfb9cef..00000000
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/PeerAuth.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.api.server.spi;
-
-import com.google.api.server.spi.auth.EndpointsPeerAuthenticator;
-import com.google.api.server.spi.config.PeerAuthenticator;
-import com.google.api.server.spi.config.Singleton;
-import com.google.api.server.spi.config.model.ApiMethodConfig;
-import com.google.api.server.spi.request.Attribute;
-import com.google.common.annotations.VisibleForTesting;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Utilities used to do peer authorization.
- */
-public class PeerAuth {
- private static final Singleton.Instantiator INSTANTIATOR
- = new Singleton.Instantiator(new EndpointsPeerAuthenticator());
-
- /**
- * Must be used to instantiate new {@link PeerAuthenticator}s to honor
- * {@link com.google.api.server.spi.config.Singleton} contract.
- *
- * @return a new instance of clazz, or an existing one if clazz is annotated with @{@link
- * com.google.api.server.spi.config.Singleton}
- */
- public static PeerAuthenticator instantiatePeerAuthenticator(Class extends PeerAuthenticator> clazz) {
- return INSTANTIATOR.getInstanceOrDefault(clazz);
- }
-
- private final HttpServletRequest request;
- private final Attribute attr;
- private final ApiMethodConfig config;
-
- @VisibleForTesting
- PeerAuth(HttpServletRequest request) {
- this.request = request;
- attr = Attribute.from(request);
- config = attr.get(Attribute.API_METHOD_CONFIG);
- }
-
- static PeerAuth from(HttpServletRequest request) {
- return new PeerAuth(request);
- }
-
- @VisibleForTesting
- Iterable getPeerAuthenticatorInstances() {
- return INSTANTIATOR.getInstancesOrDefault(config.getPeerAuthenticators());
- }
-
- boolean authorizePeer() {
- if (!attr.isEnabled(Attribute.RESTRICT_SERVLET)) {
- return true;
- }
- Iterable peerAuthenticators = getPeerAuthenticatorInstances();
- if (peerAuthenticators != null) {
- for (PeerAuthenticator peerAuthenticator : peerAuthenticators) {
- if (!peerAuthenticator.authenticate(request)) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/RequestUtil.java b/endpoints-framework/src/main/java/com/google/api/server/spi/RequestUtil.java
new file mode 100644
index 00000000..e7617e6c
--- /dev/null
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/RequestUtil.java
@@ -0,0 +1,27 @@
+package com.google.api.server.spi;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class RequestUtil {
+
+ public static String getOriginalRequestUrl(HttpServletRequest req) {
+ String protocolHeader = req.getHeader("X-Forwarded-Proto");
+ String requestUrl = stripRedundantPorts(req.getRequestURL().toString());
+ if (protocolHeader != null && protocolHeader.equalsIgnoreCase("https")) {
+ requestUrl = requestUrl.replaceFirst("^http:", "https:");
+ }
+ return requestUrl;
+ }
+
+ private static String stripRedundantPorts(String url) {
+ if (url == null) {
+ return null;
+ } else if (url.startsWith("http:") && url.contains(":80/")) {
+ return url.replace(":80/", "/");
+ } else if (url.startsWith("https:") && url.contains(":443/")) {
+ return url.replace(":443/", "/");
+ }
+ return url;
+ }
+
+}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/ServiceException.java b/endpoints-framework/src/main/java/com/google/api/server/spi/ServiceException.java
index d90f97b8..b010f3f3 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/ServiceException.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/ServiceException.java
@@ -15,6 +15,12 @@
*/
package com.google.api.server.spi;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
+
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
@@ -24,10 +30,16 @@
*/
public class ServiceException extends Exception {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ /** Reserved keywords, cannot be set as an extra field name. */
+ public static final ImmutableList EXTRA_FIELDS_RESERVED_NAMES = ImmutableList.of("domain", "message", "reason");
+
protected final int statusCode;
protected final String reason;
protected final String domain;
protected Level logLevel;
+ private final Map extraFields = new HashMap<>();
public ServiceException(int statusCode, String statusMessage) {
super(statusMessage);
@@ -102,6 +114,84 @@ public Map getHeaders() {
return null;
}
+ /**
+ * Associates to this exception an extra field as a field name/value pair. If a field
+ * with the same name was previously set, the old value is replaced by the specified
+ * value.
+ * @return this
+ * @throws NullPointerException if {@code fieldName} is {@code null}.
+ * @throws IllegalArgumentException if {@code fieldName} is one of the reserved field
+ * names {@link #EXTRA_FIELDS_RESERVED_NAMES}.
+ */
+ public ServiceException putExtraField(String fieldName, String value) {
+ return putExtraFieldInternal(fieldName, value);
+ }
+
+ /**
+ * Associates to this exception an extra field as a field name/value pair. If a field
+ * with the same name was previously set, the old value is replaced by the specified
+ * value.
+ * @return this
+ * @throws NullPointerException if {@code fieldName} is {@code null}.
+ * @throws IllegalArgumentException if {@code fieldName} is one of the reserved field
+ * names {@link #EXTRA_FIELDS_RESERVED_NAMES}.
+ */
+ public ServiceException putExtraField(String fieldName, Boolean value) {
+ return putExtraFieldInternal(fieldName, value);
+ }
+
+ /**
+ * Associates to this exception an extra field as a field name/value pair. If a field
+ * with the same name was previously set, the old value is replaced by the specified
+ * value.
+ * @return this
+ * @throws NullPointerException if {@code fieldName} is {@code null}.
+ * @throws IllegalArgumentException if {@code fieldName} is one of the reserved field
+ * names {@link #EXTRA_FIELDS_RESERVED_NAMES}.
+ */
+ public ServiceException putExtraField(String fieldName, Number value) {
+ return putExtraFieldInternal(fieldName, value);
+ }
+
+ /**
+ * Associates to this exception an extra field as a field name/value pair. If a field
+ * with the same name was previously set, the old value is replaced by the specified
+ * value.
+ * This unsafe version accepts any POJO as is:
+ *
+ *
the object should be serializable
+ *
no defensive copy nor conversion are made. So {@code value} should not be modified
+ * or reused after the call of this method.
+ *
+ * These constraints must be taken into consideration when overriding this method.
+ * @return this
+ * @throws NullPointerException if {@code fieldName} is {@code null}.
+ * @throws IllegalArgumentException if {@code fieldName} is one of the reserved field
+ * names {@link #EXTRA_FIELDS_RESERVED_NAMES}.
+ */
+ protected ServiceException putExtraFieldUnsafe(String fieldName, Object value) {
+ return putExtraFieldInternal(fieldName, value);
+ }
+
+ private ServiceException putExtraFieldInternal(String fieldName, Object value) {
+ Preconditions.checkNotNull(fieldName);
+ Preconditions.checkArgument(!EXTRA_FIELDS_RESERVED_NAMES.contains(fieldName), "The field name '%s' is reserved", fieldName);
+ final Object previousValue = extraFields.put(fieldName, value);
+ if (previousValue != null) {
+ logger.atFine().log("Replaced extra field %s: %s => %s", fieldName, previousValue, value);
+ }
+ return this;
+ }
+
+ /**
+ * Gets the extra fields. The extra fields are returned in an unmodifiable map,
+ * each field name/value pair is a map entry. The map is empty if no extra field
+ * has been added.
+ */
+ public final Map getExtraFields() {
+ return Collections.unmodifiableMap(extraFields);
+ }
+
public Level getLogLevel() {
return logLevel == null ? getDefaultLoggingLevel(statusCode) : logLevel;
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/ServletInitializationParameters.java b/endpoints-framework/src/main/java/com/google/api/server/spi/ServletInitializationParameters.java
index 9c6a5b7e..877d16ef 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/ServletInitializationParameters.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/ServletInitializationParameters.java
@@ -19,10 +19,12 @@
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@@ -39,6 +41,9 @@ public abstract class ServletInitializationParameters {
private static final String EXCEPTION_COMPATIBILITY = "enableExceptionCompatibility";
private static final String PRETTY_PRINT = "prettyPrint";
private static final String ADD_CONTENT_LENGTH = "addContentLength";
+ private static final String API_EXPLORER_URL_TEMPLATE = "apiExplorerUrlTemplate";
+ private static final String PARAMETER_VALIDATION = "enableValidation";
+ private static final String CONTENT_TYPE_VALIDATION = "enableContentTypeValidation";
private static final Splitter CSV_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
private static final Joiner CSV_JOINER = Joiner.on(',').skipNulls();
@@ -54,14 +59,6 @@ public String apply(Class> clazz) {
*/
public abstract ImmutableSet> getServiceClasses();
- /**
- * Returns if the SPI servlet is restricted.
- *
- * @deprecated No longer serves any purpose and will be removed in a future release
- */
- @Deprecated
- public abstract boolean isServletRestricted();
-
/**
* Returns if client ID whitelisting is enabled.
*/
@@ -92,14 +89,29 @@ public String apply(Class> clazz) {
*/
public abstract boolean isAddContentLength();
+ /**
+ * Returns whether the request parameter validation is enabled.
+ */
+ public abstract boolean isParameterValidationEnabled();
+
+ /**
+ * Returns whether the request content type validation is enabled.
+ */
+ public abstract boolean isContentTypeValidationEnabled();
+
+ @Nullable
+ public abstract String getApiExplorerUrlTemplate();
+
public static Builder builder() {
return new AutoValue_ServletInitializationParameters.Builder()
- .setServletRestricted(true)
.setClientIdWhitelistEnabled(true)
.setIllegalArgumentBackendError(false)
.setExceptionCompatibilityEnabled(true)
.setPrettyPrintEnabled(true)
- .setAddContentLength(false);
+ .setAddContentLength(false)
+ .setParameterValidationEnabled(true)
+ .setContentTypeValidationEnabled(false)
+ .setApiExplorerUrlTemplate(null);
}
/**
@@ -130,24 +142,6 @@ public Builder addServiceClasses(Iterable extends Class>> serviceClasses) {
*/
public abstract Builder setServiceClasses(ImmutableSet> clazzes);
- /**
- * Sets if the servlet is restricted. Defaults to {@code true}.
- *
- * @deprecated No longer serves any purpose and will be removed in a future release
- */
- @Deprecated
- public abstract Builder setServletRestricted(boolean servletRestricted);
-
- /**
- * Sets if the servlet is restricted. Retained for API compatibility.
- *
- * @deprecated Retained for API compatibility
- */
- @Deprecated
- public Builder setRestricted(boolean servletRestricted) {
- return setServletRestricted(servletRestricted);
- }
-
/**
* Sets if the client ID whitelist is enabled, defaulting to {@code true}.
*/
@@ -160,10 +154,14 @@ public Builder setRestricted(boolean servletRestricted) {
public abstract Builder setIllegalArgumentBackendError(boolean illegalArgumentBackendError);
/**
- * Sets if v1.0 style exceptions should be returned to users. In v1.0, certain codes are not
- * permissible, and other codes are translated to other status codes. Defaults to {@code true}.
+ * Sets if request parameter validation should be enabled. Defaults to {@code true}.
*/
- public abstract Builder setExceptionCompatibilityEnabled(boolean exceptionCompatibility);
+ public abstract Builder setParameterValidationEnabled(boolean enabledParameterValidation);
+
+ /**
+ * Sets if request content type validation should be enabled. Defaults to {@code false}.
+ */
+ public abstract Builder setContentTypeValidationEnabled(boolean enabledContentTypeValidation);
/**
* Sets if pretty printing should be enabled for responses by default. Defaults to {@code true}.
@@ -175,6 +173,20 @@ public Builder setRestricted(boolean servletRestricted) {
*/
public abstract Builder setAddContentLength(boolean addContentLength);
+ /**
+ * Sets the url template for the API explorer.
+ * The only supported variable is ${apiBase}.
+ * Given https://myapp.com/_ah/api/explorer, ${apiBase} is set to https://myapp.com/_ah/api.
+ * Defaults to http://apis-explorer.appspot.com/apis-explorer/?base=${apiBase} if not set.
+ */
+ public abstract Builder setApiExplorerUrlTemplate(String urlTemplate);
+
+ /**
+ * Sets if v1.0 style exceptions should be returned to users. In v1.0, certain codes are not
+ * permissible, and other codes are translated to other status codes. Defaults to {@code true}.
+ */
+ public abstract Builder setExceptionCompatibilityEnabled(boolean exceptionCompatibility);
+
abstract ServletInitializationParameters autoBuild();
public ServletInitializationParameters build() {
@@ -195,10 +207,6 @@ public static ServletInitializationParameters fromServletConfig(
builder.addServiceClass(getClassForName(serviceClassName, classLoader));
}
}
- String servletRestricted = config.getInitParameter(RESTRICTED);
- if (servletRestricted != null) {
- builder.setServletRestricted(parseBoolean(servletRestricted, RESTRICTED));
- }
String clientIdWhitelist = config.getInitParameter(CLIENT_ID_WHITELIST_ENABLED);
if (clientIdWhitelist != null) {
builder.setClientIdWhitelistEnabled(
@@ -222,6 +230,17 @@ public static ServletInitializationParameters fromServletConfig(
if (addContentLength != null) {
builder.setAddContentLength(parseBoolean(addContentLength, ADD_CONTENT_LENGTH));
}
+ String enabledParameterValidation = config.getInitParameter(PARAMETER_VALIDATION);
+ if (enabledParameterValidation != null) {
+ builder.setParameterValidationEnabled(
+ parseBoolean(enabledParameterValidation, PARAMETER_VALIDATION));
+ }
+ String enabledContentTypeValidation = config.getInitParameter(CONTENT_TYPE_VALIDATION);
+ if (enabledContentTypeValidation != null) {
+ builder.setContentTypeValidationEnabled(
+ parseBoolean(enabledContentTypeValidation, CONTENT_TYPE_VALIDATION));
+ }
+ builder.setApiExplorerUrlTemplate(config.getInitParameter(API_EXPLORER_URL_TEMPLATE));
}
return builder.build();
}
@@ -249,15 +268,17 @@ private static Class> getClassForName(String className, ClassLoader classLoade
/**
* Returns the parameters as a {@link java.util.Map} of parameter name to {@link String} value.
*/
- public ImmutableMap asMap() {
- return ImmutableMap.builder()
- .put(SERVICES, CSV_JOINER.join(Iterables.transform(getServiceClasses(), CLASS_TO_NAME)))
- .put(RESTRICTED, Boolean.toString(isServletRestricted()))
- .put(CLIENT_ID_WHITELIST_ENABLED, Boolean.toString(isClientIdWhitelistEnabled()))
- .put(ILLEGAL_ARGUMENT_BACKEND_ERROR, Boolean.toString(isIllegalArgumentBackendError()))
- .put(EXCEPTION_COMPATIBILITY, Boolean.toString(isExceptionCompatibilityEnabled()))
- .put(PRETTY_PRINT, Boolean.toString(isPrettyPrintEnabled()))
- .put(ADD_CONTENT_LENGTH, Boolean.toString(isAddContentLength()))
- .build();
+ public Map asMap() {
+ return new HashMap() {{
+ put(SERVICES, CSV_JOINER.join(Iterables.transform(getServiceClasses(), CLASS_TO_NAME)));
+ put(CLIENT_ID_WHITELIST_ENABLED, Boolean.toString(isClientIdWhitelistEnabled()));
+ put(ILLEGAL_ARGUMENT_BACKEND_ERROR, Boolean.toString(isIllegalArgumentBackendError()));
+ put(EXCEPTION_COMPATIBILITY, Boolean.toString(isExceptionCompatibilityEnabled()));
+ put(PRETTY_PRINT, Boolean.toString(isPrettyPrintEnabled()));
+ put(ADD_CONTENT_LENGTH, Boolean.toString(isAddContentLength()));
+ put(PARAMETER_VALIDATION, Boolean.toString(isParameterValidationEnabled()));
+ put(CONTENT_TYPE_VALIDATION, Boolean.toString(isContentTypeValidationEnabled()));
+ put(API_EXPLORER_URL_TEMPLATE, getApiExplorerUrlTemplate());
+ }};
}
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/SystemService.java b/endpoints-framework/src/main/java/com/google/api/server/spi/SystemService.java
index 36873da8..fa8c4d83 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/SystemService.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/SystemService.java
@@ -34,6 +34,7 @@
import com.google.api.server.spi.request.ParamReader;
import com.google.api.server.spi.response.BadRequestException;
import com.google.api.server.spi.response.InternalServerErrorException;
+import com.google.api.server.spi.response.RedirectException;
import com.google.api.server.spi.response.ResultWriter;
import com.google.api.server.spi.response.UnauthorizedException;
import com.google.common.base.Function;
@@ -340,21 +341,23 @@ public Method findServiceMethod(Object service, String methodName) throws Servic
* Invokes a {@code method} on a {@code service} given a {@code paramReader} to read parameters
* and a {@code resultWriter} to write result.
*/
- public void invokeServiceMethod(Object service, Method method, ParamReader paramReader,
- ResultWriter resultWriter) throws IOException {
+ public void invokeServiceMethod(Object service, Method method, int status, ParamReader paramReader,
+ ResultWriter resultWriter) throws IOException, RedirectException {
try {
Object[] params = paramReader.read();
logger.atFine().log("params=%s (String)", Arrays.toString(params));
Object response = method.invoke(service, params);
- resultWriter.write(response);
+ resultWriter.write(response, status);
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.atSevere().withCause(e).log("exception occurred while calling backend method");
resultWriter.writeError(new BadRequestException(e));
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
Level level = Level.INFO;
- if (cause instanceof ServiceException) {
+ if (cause instanceof RedirectException) {
+ throw (RedirectException) cause;
+ } else if (cause instanceof ServiceException) {
resultWriter.writeError((ServiceException) cause);
} else if (cause instanceof IllegalArgumentException) {
resultWriter.writeError(
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/TypeLoader.java b/endpoints-framework/src/main/java/com/google/api/server/spi/TypeLoader.java
index c93afe27..dbafdc95 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/TypeLoader.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/TypeLoader.java
@@ -191,6 +191,18 @@ private static Map> createAnnotationTypes(
loadAnnotation(classLoader, "com.google.api.server.spi.config.Named"));
annotationTypes.put("Nullable",
loadAnnotation(classLoader, "com.google.api.server.spi.config.Nullable"));
+ annotationTypes.put("Pattern",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.Pattern"));
+ annotationTypes.put("Min",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.Min"));
+ annotationTypes.put("Max",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.Max"));
+ annotationTypes.put("DecimalMin",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.DecimalMin"));
+ annotationTypes.put("DecimalMax",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.DecimalMax"));
+ annotationTypes.put("Size",
+ loadAnnotation(classLoader, "jakarta.validation.constraints.Size"));
return Collections.unmodifiableMap(annotationTypes);
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsAuthenticator.java b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsAuthenticator.java
index ecdb7f7e..b5c56b48 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsAuthenticator.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsAuthenticator.java
@@ -38,7 +38,7 @@ public class EndpointsAuthenticator implements Authenticator {
public EndpointsAuthenticator() {
this.jwtAuthenticator = new GoogleJwtAuthenticator();
- this.appEngineAuthenticator = new GoogleAppEngineAuthenticator();
+ this.appEngineAuthenticator = EnvUtil.isRunningOnAppEngine() ? new GoogleAppEngineAuthenticator() : null;
this.oauth2Authenticator = new GoogleOAuth2Authenticator();
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsPeerAuthenticator.java b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsPeerAuthenticator.java
deleted file mode 100644
index b803cc76..00000000
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/EndpointsPeerAuthenticator.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.api.server.spi.auth;
-
-import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
-import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
-import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
-import com.google.api.server.spi.Client;
-import com.google.api.server.spi.EnvUtil;
-import com.google.api.server.spi.config.PeerAuthenticator;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-
-import com.google.common.flogger.FluentLogger;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.logging.Logger;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * The default peer authenticator. It verify the request is from Google Cloud Endpoints frontend. It
- * is different from EndpointsAuthenticator, which authenticates the end user.
- */
-public class EndpointsPeerAuthenticator implements PeerAuthenticator {
- @VisibleForTesting
- static final String ISSUER = "https://www.cloudendpointsapis.com";
- @VisibleForTesting
- static final String SIGNER = "cloud-endpoints-signer@system.gserviceaccount.com";
- @VisibleForTesting
- static final String HEADER_APPENGINE_PEER = "X-Appengine-Peer";
- @VisibleForTesting
- static final String APPENGINE_PEER = "apiserving";
- @VisibleForTesting
- static final String HEADER_PEER_AUTHORIZATION = "Peer-Authorization";
-
- private static final String PUBLIC_CERT_URL =
- "https://www.googleapis.com/service_accounts/v1/metadata/x509/" + SIGNER;
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private static final ImmutableSet localHostAddresses = getLocalHostAddresses();
-
- private final GoogleJwtAuthenticator jwtAuthenticator;
-
- private static ImmutableSet getLocalHostAddresses() {
- ImmutableSet.Builder builder = new ImmutableSet.Builder<>();
- try {
- builder.add(InetAddress.getLocalHost().getHostAddress());
- } catch (IOException e) {
- // try next.
- }
- try {
- builder.add(InetAddress.getByName(null).getHostAddress());
- } catch (IOException e) {
- // try next.
- }
- try {
- for (InetAddress inetAddress : InetAddress.getAllByName("localhost")) {
- builder.add(inetAddress.getHostAddress());
- }
- } catch (IOException e) {
- // check at the end.
- }
- ImmutableSet localHostSet = builder.build();
- if (localHostSet.isEmpty()) {
- logger.atWarning().log("Unable to lookup local addresses.");
- }
- return localHostSet;
- }
-
- public EndpointsPeerAuthenticator() {
- Client client = Client.getInstance();
- GooglePublicKeysManager keyManager = new GooglePublicKeysManager.Builder(
- client.getHttpTransport(), client.getJsonFactory()).setPublicCertsEncodedUrl(
- PUBLIC_CERT_URL).build();
- GoogleIdTokenVerifier verifier =
- new GoogleIdTokenVerifier.Builder(keyManager).setIssuer(ISSUER).build();
- jwtAuthenticator = new GoogleJwtAuthenticator(verifier);
- }
-
- @VisibleForTesting
- public EndpointsPeerAuthenticator(GoogleJwtAuthenticator jwtAuthenticator) {
- this.jwtAuthenticator = jwtAuthenticator;
- }
-
- @Override
- public boolean authenticate(HttpServletRequest request) {
- // Preserve current check for App Engine Env.
- if (EnvUtil.isRunningOnAppEngine()) {
- return APPENGINE_PEER.equals(request.getHeader(HEADER_APPENGINE_PEER));
- }
-
- // Skip peer verification for localhost request.
- if (localHostAddresses.contains(request.getRemoteAddr())) {
- logger.atFine().log("Skip endpoints peer verication from localhost.");
- return true;
- }
- // Verify peer token, signer and audience.
- GoogleIdToken idToken =
- jwtAuthenticator.verifyToken(request.getHeader(HEADER_PEER_AUTHORIZATION));
- if (idToken == null || !SIGNER.equals(idToken.getPayload().getEmail())
- || !matchHostAndPort(idToken, request)) {
- return false;
- }
- return true;
- }
-
- private boolean matchHostAndPort(GoogleIdToken idToken, HttpServletRequest request) {
- URL urlFromIdToken;
- URL urlFromRequest;
- try {
- urlFromIdToken = new URL((String) idToken.getPayload().getAudience());
- urlFromRequest = new URL(request.getRequestURL().toString());
- return urlFromIdToken.getHost().equals(urlFromRequest.getHost())
- && getPort(urlFromIdToken) == getPort(urlFromRequest);
- } catch (MalformedURLException e) {
- logger.atWarning().log("Invalid URL from request");
- return false;
- }
- }
-
- private int getPort(URL url) {
- int port = url.getPort();
- return port == -1 ? url.getDefaultPort() : port;
- }
-}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdToken.java b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdToken.java
new file mode 100644
index 00000000..7f67fc49
--- /dev/null
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdToken.java
@@ -0,0 +1,40 @@
+package com.google.api.server.spi.auth;
+
+import java.io.IOException;
+
+import com.google.api.client.auth.openidconnect.IdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.webtoken.JsonWebSignature;
+import com.google.api.client.util.Key;
+
+public class GoogleCustomIdToken extends GoogleIdToken {
+
+ public GoogleCustomIdToken(Header header, Payload payload, byte[] signatureBytes, byte[] signedContentBytes) {
+ super(header, payload, signatureBytes, signedContentBytes);
+ }
+
+ public static GoogleCustomIdToken parse(JsonFactory jsonFactory, String idTokenString) throws IOException {
+ JsonWebSignature jws = JsonWebSignature.parser(jsonFactory).setPayloadClass(Payload.class).parse(idTokenString);
+ return new GoogleCustomIdToken(jws.getHeader(), (Payload) jws.getPayload(), jws.getSignatureBytes(), jws.getSignedContentBytes());
+ }
+
+ public GoogleCustomIdToken.Payload getPayload() {
+ return (GoogleCustomIdToken.Payload)super.getPayload();
+ }
+
+ public static class Payload extends GoogleIdToken.Payload {
+
+ @Key("primaryEmail")
+ private String primaryEmail;
+
+ public String getPrimaryEmail() {
+ return primaryEmail;
+ }
+
+ public void setPrimaryEmail(String primaryEmail) {
+ this.primaryEmail = primaryEmail;
+ }
+
+ }
+}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdTokenVerifier.java b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdTokenVerifier.java
new file mode 100644
index 00000000..6a46d9c5
--- /dev/null
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleCustomIdTokenVerifier.java
@@ -0,0 +1,69 @@
+package com.google.api.server.spi.auth;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Collection;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.util.Clock;
+
+public class GoogleCustomIdTokenVerifier extends GoogleIdTokenVerifier {
+
+ public GoogleCustomIdTokenVerifier(HttpTransport transport, JsonFactory jsonFactory) {
+ super(transport, jsonFactory);
+ }
+ protected GoogleCustomIdTokenVerifier(GoogleCustomIdTokenVerifier.Builder builder) {
+ super(builder);
+ }
+ public GoogleCustomIdTokenVerifier(GooglePublicKeysManager publicKeys) {
+ this(new GoogleCustomIdTokenVerifier.Builder(publicKeys));
+ }
+
+
+
+ public static class Builder extends GoogleIdTokenVerifier.Builder {
+
+ public Builder(HttpTransport transport, JsonFactory jsonFactory) {
+ super(transport, jsonFactory);
+ }
+ public Builder(GooglePublicKeysManager publicKeys) {
+ super(publicKeys);
+ }
+
+ @Override
+ public GoogleCustomIdTokenVerifier.Builder setIssuers(Collection issuers) {
+ return (Builder) super.setIssuers(issuers);
+ }
+
+ @Override
+ public GoogleCustomIdTokenVerifier.Builder setAudience(Collection audience) {
+ return (Builder) super.setAudience(audience);
+ }
+
+ @Override
+ public GoogleCustomIdTokenVerifier.Builder setClock(Clock clock) {
+ return (Builder) super.setClock(clock);
+ }
+
+ @Override
+ public GoogleCustomIdTokenVerifier.Builder setIssuer(String issuer) {
+ return (Builder) super.setIssuer(issuer);
+ }
+
+ public GoogleCustomIdTokenVerifier build() {
+ return new GoogleCustomIdTokenVerifier(this);
+ }
+
+ }
+
+ @Override
+ public GoogleCustomIdToken verify(String idTokenString) throws GeneralSecurityException, IOException {
+ GoogleCustomIdToken idToken = GoogleCustomIdToken.parse(this.getJsonFactory(), idTokenString);
+ return this.verify(idToken) ? idToken : null;
+ }
+
+}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleJwtAuthenticator.java b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleJwtAuthenticator.java
index f24fdea5..bf5dba79 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleJwtAuthenticator.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/auth/GoogleJwtAuthenticator.java
@@ -15,8 +15,6 @@
*/
package com.google.api.server.spi.auth;
-import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
-import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.server.spi.Client;
import com.google.api.server.spi.auth.common.User;
import com.google.api.server.spi.config.Authenticator;
@@ -35,19 +33,19 @@
@Singleton
public class GoogleJwtAuthenticator implements Authenticator {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final GoogleIdTokenVerifier verifier;
+ private final GoogleCustomIdTokenVerifier verifier;
public GoogleJwtAuthenticator() {
- this(new GoogleIdTokenVerifier.Builder(Client.getInstance().getHttpTransport(),
+ this(new GoogleCustomIdTokenVerifier.Builder(Client.getInstance().getHttpTransport(),
Client.getInstance().getJsonFactory()).build());
}
- public GoogleJwtAuthenticator(GoogleIdTokenVerifier verifier) {
+ public GoogleJwtAuthenticator(GoogleCustomIdTokenVerifier verifier) {
this.verifier = verifier;
}
@VisibleForTesting
- GoogleIdToken verifyToken(String token) {
+ GoogleCustomIdToken verifyToken(String token) {
if (token == null) {
return null;
}
@@ -71,7 +69,7 @@ public User authenticate(HttpServletRequest request) {
return null;
}
- GoogleIdToken idToken = verifyToken(token);
+ GoogleCustomIdToken idToken = verifyToken(token);
if (idToken == null) {
return null;
}
@@ -94,7 +92,7 @@ public User authenticate(HttpServletRequest request) {
logger.atWarning().log("Audience is not allowed: %s", audience);
return null;
}
-
+
String userId = idToken.getPayload().getSubject();
String email = idToken.getPayload().getEmail();
User user = (userId == null && email == null) ? null : new User(userId, email);
@@ -102,9 +100,9 @@ public User authenticate(HttpServletRequest request) {
com.google.appengine.api.users.User appEngineUser =
(email == null) ? null : new com.google.appengine.api.users.User(email, "");
attr.set(Attribute.AUTHENTICATED_APPENGINE_USER, appEngineUser);
- logger.atFine().log("appEngineUser = %s", appEngineUser);
+ logger.atInfo().log("appEngineUser = %s", appEngineUser);
} else {
- logger.atFine().log("user = %s", user);
+ logger.atInfo().log("user = %s", user);
}
return user;
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/Api.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/Api.java
index 3edbf46f..20bd2d06 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/Api.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/Api.java
@@ -26,16 +26,8 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Api {
- public static final int UNSPECIFIED_INT = Integer.MIN_VALUE;
- public static final String UNSPECIFIED_STRING_FOR_LIST = "_UNSPECIFIED_LIST_STRING_VALUE";
-
- /**
- * Frontend root URL, e.g. "https://example.appspot.com/_ah/api". All api
- * methods will be exposed below this path. This will default to
- * "https://yourapp.appspot.com/_ah/api".
- */
- @Deprecated
- String root() default "";
+ int UNSPECIFIED_INT = Integer.MIN_VALUE;
+ String UNSPECIFIED_STRING_FOR_LIST = "_UNSPECIFIED_LIST_STRING_VALUE";
/**
* Name of the API, e.g. "guestbook". This is used as the prefix for all api
@@ -73,14 +65,6 @@
*/
String documentationLink() default "";
- /**
- * Backend root URL, e.g. "https://example.appspot.com/_ah/spi". This is the root of all backend
- * method calls. This will default to "https://yourapp.appspot.com/_ah/spi". Non-secure http URLs
- * will be automatically converted to use https.
- */
- @Deprecated
- String backendRoot() default "";
-
/**
* Configures authentication information. See {@link ApiAuth} for details.
*/
@@ -146,13 +130,6 @@ ApiIssuerAudience[] issuerAudiences() default {
*/
Class extends Authenticator>[] authenticators() default {Authenticator.class};
- /**
- * Custom peer authenticators. Applies to all methods of the API unless overridden by
- * {@code @ApiClass#peerAuthenticators} or {@code @ApiMethod#peerAuthenticators}. See
- * {@link PeerAuthenticator}.
- */
- Class extends PeerAuthenticator>[] peerAuthenticators() default {PeerAuthenticator.class};
-
/**
* {@code true} if this API configuration is used as the base for another. Should be {@code false}
* for most situations.
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiClass.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiClass.java
index 351821cc..cff9e023 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiClass.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiClass.java
@@ -77,12 +77,6 @@ ApiIssuerAudience[] issuerAudiences() default {
*/
Class extends Authenticator>[] authenticators() default {Authenticator.class};
- /**
- * Custom peer authenticators, applicable to all methods of the API class unless overridden by
- * {@code @ApiMethod#peerAuthenticators}.
- */
- Class extends PeerAuthenticator>[] peerAuthenticators() default {PeerAuthenticator.class};
-
/**
* {@code AnnotationBoolean.TRUE} to request that overriding configuration be loaded from the
* appengine datastore.
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiIssuer.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiIssuer.java
index bc42ba91..c14899bf 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiIssuer.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiIssuer.java
@@ -33,4 +33,15 @@
* The location of the JSON web key set used to verify tokens generated by this issuer.
*/
String jwksUri() default "";
+
+ /**
+ * The authorization URL to use for the authorization flow.
+ */
+ String authorizationUrl() default "";
+
+ /**
+ * When true, scopes will be used in authorization flow.
+ */
+ boolean useScopesInAuthFlow() default false;
+
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethod.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethod.java
index 3065fa77..e8a18f2e 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethod.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethod.java
@@ -15,6 +15,8 @@
*/
package com.google.api.server.spi.config;
+import static com.google.api.server.spi.config.model.ApiMethodConfig.RESPONSE_STATUS_UNSPECIFIED;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -68,14 +70,9 @@ public static class HttpMethod {
String httpMethod() default "";
/**
- * Cache-Control header settings for this method. See
- * {@link ApiMethodCacheControl} for details.
- *
- * @deprecated ApiMethodCacheControl is deprecated and will be removed in a future version of
- * Cloud Endpoints.
+ * The response status on success. If not set, the value is 200 or 204 if there is no content returned.
*/
- @Deprecated
- ApiMethodCacheControl cacheControl() default @ApiMethodCacheControl;
+ int responseStatus() default RESPONSE_STATUS_UNSPECIFIED;
/**
* Set frontend auth level.
@@ -113,11 +110,6 @@ ApiIssuerAudience[] issuerAudiences() default {
*/
Class extends Authenticator>[] authenticators() default {Authenticator.class};
- /**
- * Custom peer authenticators used to verify peer for this method.
- */
- Class extends PeerAuthenticator>[] peerAuthenticators() default {PeerAuthenticator.class};
-
/**
* Whether or not API method should be ignored.
*/
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethodCacheControl.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethodCacheControl.java
deleted file mode 100644
index 49141f2a..00000000
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiMethodCacheControl.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.api.server.spi.config;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for configuration of API method cache control.
- * @deprecated ApiMethodCacheControl is deprecated and will be removed in a future version of
- * Cloud Endpoints.
- */
-// TODO: Delete this after a sufficient deprecation period.
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-@Deprecated
-public @interface ApiMethodCacheControl {
-
- /**
- * Disables caching of this method. The default value is true, so merely
- * adding this annotation to your method config will disable caching for that
- * method, unless you set this field to {@code false}.
- */
- boolean noCache() default true;
-
- /**
- * Overrides the maximum age to cache responses from this method.
- */
- int maxAge() default 0;
-}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiResourceProperty.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiResourceProperty.java
index 10dd0eb8..acd58e92 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiResourceProperty.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/ApiResourceProperty.java
@@ -34,11 +34,20 @@
String name() default "";
/**
- * The description that the property represented by the annotated getter, setter, or field should appear
- * as in the API.
+ * The description that the property represented by the annotated getter, setter, or field should
+ * appear as in the API.
*/
String description() default "";
+ /**
+ * Whether or not the property represented by the annotated getter, setter or field is "required":
+ * - For requests, indicates the property is required for the resource to be accepted
+ * - For responses, indicates the property will be returned by the server (before applying
+ * partial response filtering)
+ * In both cases, this is only a "hint": this is not enforced in any way.
+ */
+ AnnotationBoolean required() default AnnotationBoolean.UNSPECIFIED;
+
/**
* Whether or not the property represented by the annotated getter, setter or field should be
* ignored for the API.
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/Description.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/Description.java
index 3e193911..877d052e 100644
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/Description.java
+++ b/endpoints-framework/src/main/java/com/google/api/server/spi/config/Description.java
@@ -21,14 +21,17 @@
import java.lang.annotation.Target;
/**
- * Annotation to specify the description of an API parameter or enum constants.
+ * Annotation to specify the description of a method parameter, enum type, enum constant or
+ * resource (type used as request body).
+ * If used on an enum type, the description will only be used for the Discovery format (OpenAPI
+ * will inline enum values, as the semantics is poorer).
* The description will be ignored if the annotation is used on resource fields.
*/
-@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
/**
- * The parameter description.
+ * A description.
*/
String value() default "";
}
diff --git a/endpoints-framework/src/main/java/com/google/api/server/spi/config/PeerAuthenticator.java b/endpoints-framework/src/main/java/com/google/api/server/spi/config/PeerAuthenticator.java
deleted file mode 100644
index 10b9ded4..00000000
--- a/endpoints-framework/src/main/java/com/google/api/server/spi/config/PeerAuthenticator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.api.server.spi.config;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Peer authenticators aim to verify the peer and run before {@code Authenticator}. It returns false
- * if authentication failed and stops handling the rest of the request; true if authentication
- * succeeds and continue to execute rest of peer authenticators.
- *
- *