diff --git a/endpoints/multiple-versions/README.md b/endpoints/multiple-versions/README.md
new file mode 100644
index 00000000000..5ba505d5c4f
--- /dev/null
+++ b/endpoints/multiple-versions/README.md
@@ -0,0 +1,25 @@
+# Google Cloud Endpoints & Java with Multiple Versions
+This sample demonstrates how to use Google Cloud Endpoints using a Java backend
+that supports multiple versions.
+
+For more information, see the Google Cloud Endpoints documentation on
+[Running multiple API versions](https://cloud.google.com/endpoints/docs/multiple-api-versions).
+
+## Calling your API
+
+Please refer to the Google Cloud Endpoints
+[documentation](https://cloud.google.com/endpoints/docs/app-engine/) for App
+Engine Flexible Environment to learn about creating an API Key and calling your
+API.
+
+## Viewing the Endpoints graphs
+
+By using Endpoints, you get access to several metrics that are displayed
+graphically in the Cloud Console.
+
+To view the Endpoints graphs:
+
+1. Go to the [Endpoints section in Cloud Console](https://console.cloud.google.com/endpoints)
+ of the project you deployed your API to.
+2. Click on your API to view more detailed information about the metrics
+ collected.
diff --git a/endpoints/multiple-versions/container-engine.yaml b/endpoints/multiple-versions/container-engine.yaml
new file mode 100644
index 00000000000..718b8364648
--- /dev/null
+++ b/endpoints/multiple-versions/container-engine.yaml
@@ -0,0 +1,56 @@
+# Copyright 2015 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.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: esp-echo
+spec:
+ ports:
+ - port: 80
+ targetPort: 8081
+ protocol: TCP
+ name: http
+ selector:
+ app: esp-echo
+ type: LoadBalancer
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: esp-echo
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: esp-echo
+ spec:
+ containers:
+ # [START esp]
+ - name: esp
+ image: gcr.io/endpoints-release/endpoints-runtime:1
+ args: [
+ "-p", "8081",
+ "-a", "127.0.0.1:8080",
+ "-s", "SERVICE_NAME",
+ "-v", "SERVICE_CONFIG_ID",
+ ]
+ # [END esp]
+ ports:
+ - containerPort: 8081
+ - name: echo
+ image: gcr.io/google-samples/echo-java:1.0
+ ports:
+ - containerPort: 8080
diff --git a/endpoints/multiple-versions/openapi-v2.yaml b/endpoints/multiple-versions/openapi-v2.yaml
new file mode 100644
index 00000000000..d80ff233952
--- /dev/null
+++ b/endpoints/multiple-versions/openapi-v2.yaml
@@ -0,0 +1,125 @@
+# Copyright 2015 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.
+
+# [START swagger]
+swagger: "2.0"
+info:
+ description: "A simple Google Cloud Endpoints API example."
+ title: "Endpoints Example"
+ version: "2.0.0"
+host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog"
+# [END swagger]
+basePath: "/v2"
+consumes:
+ - "application/json"
+produces:
+ - "application/json"
+schemes:
+ - "https"
+paths:
+ "/echo":
+ post:
+ description: "Echo back a given message."
+ operationId: "echo"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Echo"
+ schema:
+ $ref: "#/definitions/echoMessage"
+ parameters:
+ -
+ description: "Message to echo"
+ in: body
+ name: message
+ required: true
+ schema:
+ $ref: "#/definitions/echoMessage"
+ "/auth/info/googlejwt":
+ get:
+ description: "Returns the requests' authentication information."
+ operationId: "auth_info_google_jwt"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Authenication info."
+ schema:
+ $ref: "#/definitions/authInfoResponse"
+ x-security:
+ -
+ google_jwt:
+ audiences:
+ # This must match the "aud" field in the JWT. You can add multiple
+ # audiences to accept JWTs from multiple clients.
+ - "echo.endpoints.sample.google.com"
+ "/auth/info/googleidtoken":
+ get:
+ description: "Returns the requests' authentication information."
+ operationId: "authInfoGoogleIdToken"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Authenication info."
+ schema:
+ $ref: "#/definitions/authInfoResponse"
+ x-security:
+ -
+ google_id_token:
+ audiences:
+ # Your OAuth2 client's Client ID must be added here. You can add
+ # multiple client IDs to accept tokens from multiple clients.
+ - "YOUR-CLIENT-ID"
+definitions:
+ echoMessage:
+ properties:
+ msg:
+ type: "string"
+ authInfoResponse:
+ properties:
+ id:
+ type: "string"
+ email:
+ type: "string"
+# This section requires all requests to any path to require an API key.
+security:
+ - api_key: []
+securityDefinitions:
+ # This section configures basic authentication with an API key.
+ api_key:
+ type: "apiKey"
+ name: "key"
+ in: "query"
+ # This section configures authentication using Google API Service Accounts
+ # to sign a json web token. This is mostly used for server-to-server
+ # communication.
+ google_jwt:
+ authorizationUrl: ""
+ flow: "implicit"
+ type: "oauth2"
+ # This must match the 'iss' field in the JWT.
+ x-google-issuer: "jwt-client.endpoints.sample.google.com"
+ # Update this with your service account's email address.
+ x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL"
+ # This section configures authentication using Google OAuth2 ID Tokens.
+ # ID Tokens can be obtained using OAuth2 clients, and can be used to access
+ # your API on behalf of a particular user.
+ google_id_token:
+ authorizationUrl: ""
+ flow: "implicit"
+ type: "oauth2"
+ x-google-issuer: "accounts.google.com"
+ x-google-jwks_uri: "https://www.googleapis.com/oauth2/v1/certs"
diff --git a/endpoints/multiple-versions/openapi.yaml b/endpoints/multiple-versions/openapi.yaml
new file mode 100644
index 00000000000..3a939f9cec6
--- /dev/null
+++ b/endpoints/multiple-versions/openapi.yaml
@@ -0,0 +1,125 @@
+# Copyright 2015 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.
+
+# [START swagger]
+swagger: "2.0"
+info:
+ description: "A simple Google Cloud Endpoints API example."
+ title: "Endpoints Example"
+ version: "1.0.0"
+host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog"
+# [END swagger]
+basePath: "/v1"
+consumes:
+ - "application/json"
+produces:
+ - "application/json"
+schemes:
+ - "https"
+paths:
+ "/echo":
+ post:
+ description: "Echo back a given message."
+ operationId: "echo"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Echo"
+ schema:
+ $ref: "#/definitions/echoMessage"
+ parameters:
+ -
+ description: "Message to echo"
+ in: body
+ name: message
+ required: true
+ schema:
+ $ref: "#/definitions/echoMessage"
+ "/auth/info/googlejwt":
+ get:
+ description: "Returns the requests' authentication information."
+ operationId: "auth_info_google_jwt"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Authenication info."
+ schema:
+ $ref: "#/definitions/authInfoResponse"
+ x-security:
+ -
+ google_jwt:
+ audiences:
+ # This must match the "aud" field in the JWT. You can add multiple
+ # audiences to accept JWTs from multiple clients.
+ - "echo.endpoints.sample.google.com"
+ "/auth/info/googleidtoken":
+ get:
+ description: "Returns the requests' authentication information."
+ operationId: "authInfoGoogleIdToken"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "Authenication info."
+ schema:
+ $ref: "#/definitions/authInfoResponse"
+ x-security:
+ -
+ google_id_token:
+ audiences:
+ # Your OAuth2 client's Client ID must be added here. You can add
+ # multiple client IDs to accept tokens from multiple clients.
+ - "YOUR-CLIENT-ID"
+definitions:
+ echoMessage:
+ properties:
+ message:
+ type: "string"
+ authInfoResponse:
+ properties:
+ id:
+ type: "string"
+ email:
+ type: "string"
+# This section requires all requests to any path to require an API key.
+security:
+ - api_key: []
+securityDefinitions:
+ # This section configures basic authentication with an API key.
+ api_key:
+ type: "apiKey"
+ name: "key"
+ in: "query"
+ # This section configures authentication using Google API Service Accounts
+ # to sign a json web token. This is mostly used for server-to-server
+ # communication.
+ google_jwt:
+ authorizationUrl: ""
+ flow: "implicit"
+ type: "oauth2"
+ # This must match the 'iss' field in the JWT.
+ x-google-issuer: "jwt-client.endpoints.sample.google.com"
+ # Update this with your service account's email address.
+ x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL"
+ # This section configures authentication using Google OAuth2 ID Tokens.
+ # ID Tokens can be obtained using OAuth2 clients, and can be used to access
+ # your API on behalf of a particular user.
+ google_id_token:
+ authorizationUrl: ""
+ flow: "implicit"
+ type: "oauth2"
+ x-google-issuer: "accounts.google.com"
+ x-google-jwks_uri: "https://www.googleapis.com/oauth2/v1/certs"
diff --git a/endpoints/multiple-versions/pom.xml b/endpoints/multiple-versions/pom.xml
new file mode 100644
index 00000000000..c0329ef52f5
--- /dev/null
+++ b/endpoints/multiple-versions/pom.xml
@@ -0,0 +1,84 @@
+
+
+
+ 4.0.0
+ war
+ 1.0-SNAPSHOT
+ com.example.endpoints
+ endpoints
+
+
+ doc-samples
+ com.google.cloud
+ 1.0.0
+ ../..
+
+
+
+ 1.8
+ 1.8
+
+ 2.6
+
+ 1.0.0
+ 9.3.8.v20160314
+
+ false
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ jar
+ provided
+
+
+
+ com.google.code.gson
+ gson
+ 2.6.2
+ compile
+
+
+ com.google.collections
+ google-collections
+ 1.0-rc2
+
+
+
+
+
+ ${project.build.directory}/${project.build.finalName}/WEB-INF/classes
+
+
+ com.google.cloud.tools
+ appengine-maven-plugin
+ ${appengine.maven.plugin}
+
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ ${jetty.maven.plugin}
+
+
+
+
diff --git a/endpoints/multiple-versions/src/main/appengine/app.yaml b/endpoints/multiple-versions/src/main/appengine/app.yaml
new file mode 100644
index 00000000000..c31a7a03045
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/appengine/app.yaml
@@ -0,0 +1,27 @@
+# Copyright 2015 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.
+
+runtime: custom
+env: flex
+
+handlers:
+- url: /.*
+ script: this field is required, but ignored
+ secure: always
+
+endpoints_api_service:
+ # The following values are to be replaced by information from the output of
+ # 'gcloud service-management deploy openapi.yaml openapi-v2.yaml' command.
+ name: ENDPOINTS SERVICE-NAME
+ config_id: ENDPOINTS CONFIG-ID
diff --git a/endpoints/multiple-versions/src/main/docker/Dockerfile b/endpoints/multiple-versions/src/main/docker/Dockerfile
new file mode 100644
index 00000000000..382823d7577
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/docker/Dockerfile
@@ -0,0 +1,19 @@
+# Copyright 2015 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.
+
+FROM gcr.io/google_appengine/jetty9
+
+ADD endpoints-1.0-SNAPSHOT.war $JETTY_BASE/webapps/root.war
+ADD . /app
+RUN chown jetty:jetty $JETTY_BASE/webapps/root.war
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/AuthInfoServlet.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/AuthInfoServlet.java
new file mode 100644
index 00000000000..88cc789bf19
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/AuthInfoServlet.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.util.Base64;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A servlet that returns authentication information.
+ * See openapi.yaml for authentication mechanisms (e.g. JWT tokens, Google ID token).
+ */
+@WebServlet("/auth/info/*")
+public class AuthInfoServlet extends HttpServlet {
+
+ @Override
+ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ String encodedInfo = req.getHeader("X-Endpoint-API-UserInfo");
+ if (encodedInfo == null || encodedInfo == "") {
+ JsonObject anon = new JsonObject();
+ anon.addProperty("id", "anonymous");
+ new Gson().toJson(anon, resp.getWriter());
+ return;
+ }
+
+ try {
+ byte[] authInfo = Base64.getDecoder().decode(encodedInfo);
+ resp.getOutputStream().write(authInfo);
+ } catch (IllegalArgumentException iae) {
+ resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ JsonObject error = new JsonObject();
+ error.addProperty("code", HttpServletResponse.SC_BAD_REQUEST);
+ error.addProperty("message", "Could not decode auth info.");
+ new Gson().toJson(error, resp.getWriter());
+ }
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/Echo.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/Echo.java
new file mode 100644
index 00000000000..d7ef4f0b962
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/Echo.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints;
+
+import com.example.endpoints.message.Message;
+import com.example.endpoints.message.MessageTranslator;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.stream.JsonReader;
+
+import java.io.IOException;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** Version agnostic echo. */
+public class Echo {
+
+ public static void echo(
+ MessageTranslator translator, HttpServletRequest req, HttpServletResponse resp)
+ throws IOException {
+ resp.addHeader("Content-Encoding", "application/json");
+
+ try {
+ JsonReader jsonReader = new JsonReader(req.getReader());
+ Message message =
+ translator.fromExternalToInternal(new Gson().fromJson(jsonReader, Map.class));
+ performTask(message);
+ new Gson().toJson(translator.fromInternalToExternal(message), resp.getWriter());
+ } catch (JsonParseException je) {
+ resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ JsonObject error = new JsonObject();
+ error.addProperty("code", HttpServletResponse.SC_BAD_REQUEST);
+ error.addProperty("message", "Body was not valid JSON.");
+ new Gson().toJson(error, resp.getWriter());
+ }
+ }
+
+ private static void performTask(Message message) {
+ message.setMessage(message.getMessage().toUpperCase());
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV1Servlet.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV1Servlet.java
new file mode 100644
index 00000000000..40befeea433
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV1Servlet.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints;
+
+import com.example.endpoints.message.MessageTranslator;
+import com.example.endpoints.message.MessageV1Translator;
+
+import java.io.IOException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** A servlet for v1 that echoes JSON message bodies. */
+@WebServlet("/v1/echo")
+public class EchoV1Servlet extends HttpServlet {
+
+ private MessageTranslator translator;
+
+ public EchoV1Servlet() {
+ this.translator = new MessageV1Translator();
+ }
+
+ @Override
+ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ Echo.echo(translator, req, resp);
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV2Servlet.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV2Servlet.java
new file mode 100644
index 00000000000..096ecb4d5e1
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/EchoV2Servlet.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints;
+
+import com.example.endpoints.message.MessageTranslator;
+import com.example.endpoints.message.MessageV2Translator;
+
+import java.io.IOException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** A servlet for v2 that echoes JSON message bodies. */
+@WebServlet("/v2/echo")
+public class EchoV2Servlet extends HttpServlet {
+
+ private MessageTranslator translator;
+
+ public EchoV2Servlet() {
+ this.translator = new MessageV2Translator();
+ }
+
+ @Override
+ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ Echo.echo(translator, req, resp);
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/Message.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/Message.java
new file mode 100644
index 00000000000..29445235e8f
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/Message.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints.message;
+
+/** Internal representation of a message. */
+public class Message {
+ private String message;
+
+ public Message(String message) {
+ this.message = message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageTranslator.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageTranslator.java
new file mode 100644
index 00000000000..35b2621a3b7
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageTranslator.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints.message;
+
+import java.util.Map;
+
+/** Translates between external and internal representations of a message. */
+public interface MessageTranslator {
+ Message fromExternalToInternal(Map externalMessage);
+
+ Map fromInternalToExternal(Message internalMessage);
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV1Translator.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV1Translator.java
new file mode 100644
index 00000000000..f246d89ca17
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV1Translator.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints.message;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+/** Translates between v1 external and internal representations of a message. */
+public class MessageV1Translator implements MessageTranslator {
+ private static final String MESSAGE_KEY = "message";
+
+ public Message fromExternalToInternal(Map v1Message) {
+ return new Message(v1Message.get(MESSAGE_KEY));
+ }
+
+ public Map fromInternalToExternal(Message internalMessage) {
+ return ImmutableMap.of(MESSAGE_KEY, internalMessage.getMessage());
+ }
+}
diff --git a/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV2Translator.java b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV2Translator.java
new file mode 100644
index 00000000000..e5e172113b0
--- /dev/null
+++ b/endpoints/multiple-versions/src/main/java/com/example/endpoints/messsage/MessageV2Translator.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 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.
+ */
+
+package com.example.endpoints.message;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+/** Translates between v2 external and internal representations of a message. */
+public class MessageV2Translator implements MessageTranslator {
+ private static final String MESSAGE_KEY = "msg";
+
+ public Message fromExternalToInternal(Map v2Message) {
+ return new Message(v2Message.get(MESSAGE_KEY));
+ }
+
+ public Map fromInternalToExternal(Message internalMessage) {
+ return ImmutableMap.of(MESSAGE_KEY, internalMessage.getMessage());
+ }
+}