Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Commit 8b52dcf

Browse files
Clément Denistangiel
authored andcommitted
Expose more EndpointsServlet internals to allow customizing JSON serialization
1 parent 6bb25ed commit 8b52dcf

File tree

4 files changed

+54
-29
lines changed

4 files changed

+54
-29
lines changed

endpoints-framework/src/main/java/com/google/api/server/spi/EndpointsServlet.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ public void init(ServletConfig config) throws ServletException {
5959
this.corsHandler = new CorsHandler();
6060
}
6161

62+
protected ServletInitializationParameters getInitParameters() {
63+
return initParameters;
64+
}
65+
66+
protected SystemService getSystemService() {
67+
return systemService;
68+
}
69+
6270
@Override
6371
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
6472
String method = getRequestMethod(request);
@@ -99,7 +107,8 @@ private PathDispatcher<EndpointsContext> createDispatcher() {
99107
MethodConfigMap methods = apiConfig.getApiClassConfig().getMethods();
100108
for (Entry<EndpointMethod, ApiMethodConfig> methodEntry : methods.entrySet()) {
101109
if (!methodEntry.getValue().isIgnored()) {
102-
handlersBuilder.add(createEndpointsMethodHandler(apiConfig, methodEntry));
110+
handlersBuilder.add(createEndpointsMethodHandler(methodEntry.getKey(),
111+
methodEntry.getValue()));
103112
}
104113
}
105114
}
@@ -132,10 +141,10 @@ private SystemService createSystemService(ClassLoader classLoader,
132141
}
133142
}
134143

135-
protected EndpointsMethodHandler createEndpointsMethodHandler(ApiConfig apiConfig,
136-
Entry<EndpointMethod, ApiMethodConfig> methodEntry) {
137-
return new EndpointsMethodHandler(initParameters, getServletContext(), methodEntry.getKey(),
138-
apiConfig, methodEntry.getValue(), systemService);
144+
protected EndpointsMethodHandler createEndpointsMethodHandler(EndpointMethod method,
145+
ApiMethodConfig methodConfig) {
146+
return new EndpointsMethodHandler(initParameters, getServletContext(), method,
147+
methodConfig, systemService);
139148
}
140149

141150
/**

endpoints-framework/src/main/java/com/google/api/server/spi/handlers/EndpointsMethodHandler.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.api.server.spi.EndpointMethod;
1919
import com.google.api.server.spi.EndpointsContext;
2020
import com.google.api.server.spi.Headers;
21+
import com.google.api.server.spi.ServiceException;
2122
import com.google.api.server.spi.ServletInitializationParameters;
2223
import com.google.api.server.spi.SystemService;
2324
import com.google.api.server.spi.config.model.ApiConfig;
@@ -56,15 +57,15 @@ public class EndpointsMethodHandler {
5657
private final String restPath;
5758

5859
public EndpointsMethodHandler(ServletInitializationParameters initParameters,
59-
ServletContext servletContext, EndpointMethod endpointMethod, ApiConfig apiConfig,
60-
ApiMethodConfig methodConfig, SystemService systemService) {
60+
ServletContext servletContext, EndpointMethod endpointMethod, ApiMethodConfig methodConfig,
61+
SystemService systemService) {
6162
this.initParameters = initParameters;
6263
this.servletContext = servletContext;
6364
this.endpointMethod = endpointMethod;
6465
this.methodConfig = methodConfig;
6566
this.systemService = systemService;
6667
this.restHandler = new RestHandler();
67-
this.restPath = createRestPath(apiConfig, methodConfig);
68+
this.restPath = createRestPath(methodConfig);
6869
}
6970

7071
public String getRestMethod() {
@@ -86,20 +87,29 @@ protected ParamReader createRestParamReader(EndpointsContext context,
8687
servletContext, serializationConfig, methodConfig);
8788
}
8889

89-
@VisibleForTesting
90+
/**
91+
* Override to customize the serialization of the response body
92+
*
93+
* @return a result writer
94+
* @throws ServiceException if the result writer customization fails
95+
*/
9096
protected ResultWriter createResultWriter(EndpointsContext context,
97+
ApiSerializationConfig serializationConfig) throws ServiceException {
98+
return _createResultWriter(context, serializationConfig);
99+
}
100+
101+
private void writeError(EndpointsContext context, ServiceException error) throws IOException {
102+
_createResultWriter(context, null).writeError(error);
103+
}
104+
105+
private ResultWriter _createResultWriter(EndpointsContext context,
91106
ApiSerializationConfig serializationConfig) {
92107
return new RestResponseResultWriter(context.getResponse(), serializationConfig,
93108
StandardParameters.shouldPrettyPrint(context),
94109
initParameters.isAddContentLength(),
95110
initParameters.isExceptionCompatibilityEnabled());
96111
}
97112

98-
private ResultWriter createErrorResultWriter(EndpointsContext context) {
99-
// TODO: Convert this to RESTful errors.
100-
return createResultWriter(context, null);
101-
}
102-
103113
private class RestHandler implements DispatcherHandler<EndpointsContext> {
104114
@Override
105115
public void handle(EndpointsContext context) throws IOException {
@@ -118,22 +128,24 @@ public void handle(EndpointsContext context) throws IOException {
118128
CorsHandler.setAccessControlAllowCredentials(response);
119129
}
120130
systemService.invokeServiceMethod(service, endpointMethod.getMethod(), reader, writer);
131+
} catch (ServiceException e) {
132+
writeError(context, e);
121133
} catch (Exception e) {
122134
// All exceptions here are unexpected, including the ServiceException that may be thrown by
123135
// the findService call. We return an internal server error and leave the details in the
124136
// backend log.
125137
logger.log(Level.WARNING, "exception occurred while invoking backend method", e);
126-
createErrorResultWriter(context)
127-
.writeError(new InternalServerErrorException("backend error"));
138+
writeError(context, new InternalServerErrorException("backend error"));
128139
}
129140
}
130141
}
131142

132-
private static String createRestPath(ApiConfig apiConfig, ApiMethodConfig methodConfig) {
143+
private static String createRestPath(ApiMethodConfig methodConfig) {
133144
// Don't include the api name or version if the path starts with a slash.
134145
if (methodConfig.getPath().startsWith("/")) {
135146
return methodConfig.getPath().substring(1);
136147
}
148+
ApiConfig apiConfig = methodConfig.getApiConfig();
137149
return String.format(
138150
"%s/%s/%s", apiConfig.getName(), apiConfig.getVersion(), methodConfig.getPath());
139151
}

endpoints-framework/src/main/java/com/google/api/server/spi/response/ServletResponseResultWriter.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,14 @@
3333
import com.fasterxml.jackson.databind.SerializerProvider;
3434
import com.fasterxml.jackson.databind.module.SimpleModule;
3535

36-
import java.io.BufferedOutputStream;
37-
import java.io.BufferedWriter;
3836
import java.io.IOException;
39-
import java.nio.charset.StandardCharsets;
4037
import java.util.Collections;
4138
import java.util.Date;
4239
import java.util.HashMap;
4340
import java.util.LinkedHashSet;
4441
import java.util.Map;
4542
import java.util.Set;
4643

47-
import javax.servlet.ServletOutputStream;
4844
import javax.servlet.http.HttpServletResponse;
4945

5046
/**
@@ -95,10 +91,20 @@ public ServletResponseResultWriter(
9591
if (prettyPrint) {
9692
objectWriter = objectWriter.with(new EndpointsPrettyPrinter());
9793
}
98-
this.objectWriter = objectWriter;
94+
this.objectWriter = configureWriter(objectWriter);
9995
this.addContentLength = addContentLength;
10096
}
10197

98+
/**
99+
* Override to add additional behavior, like partial response, etc.
100+
*
101+
* @param objectWriter the standard object writer
102+
* @return a configured writer (might be wrapped)
103+
*/
104+
protected ObjectWriter configureWriter(ObjectWriter objectWriter) {
105+
return objectWriter;
106+
}
107+
102108
@Override
103109
public void write(Object response) throws IOException {
104110
if (response == null) {

endpoints-framework/src/test/java/com/google/api/server/spi/handlers/EndpointsMethodHandlerTest.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ public void fail_findService() throws Exception {
108108
.build();
109109
TestMethodHandler handler = new TestMethodHandler(
110110
ServletInitializationParameters.builder().build(), method,
111-
apiConfig, methodConfig, systemService, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
112-
RESOURCE);
111+
methodConfig, systemService, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, RESOURCE);
113112
handler.getRestHandler().handle(context);
114113
}
115114

@@ -120,8 +119,8 @@ public void rootMethodHandler() throws Exception {
120119
apiConfig.getApiClassConfig());
121120
methodConfig.setPath("/root");
122121
TestMethodHandler handler = new TestMethodHandler(
123-
ServletInitializationParameters.builder().build(), method, apiConfig, methodConfig,
124-
systemService, 200);
122+
ServletInitializationParameters.builder().build(), method, methodConfig, systemService,
123+
200);
125124
assertThat(handler.getRestPath()).isEqualTo("root");
126125
}
127126

@@ -131,7 +130,7 @@ private TestMethodHandler createTestHandler(String methodName, Object expectedRe
131130
ApiMethodConfig methodConfig = new ApiMethodConfig(method, typeLoader,
132131
apiConfig.getApiClassConfig());
133132
return new TestMethodHandler(ServletInitializationParameters.builder().build(), method,
134-
apiConfig, methodConfig, systemService, expectedResponse, params);
133+
methodConfig, systemService, expectedResponse, params);
135134
}
136135

137136
private static class TestMethodHandler extends EndpointsMethodHandler {
@@ -140,12 +139,11 @@ private static class TestMethodHandler extends EndpointsMethodHandler {
140139
public TestMethodHandler(
141140
ServletInitializationParameters initParameters,
142141
EndpointMethod endpointMethod,
143-
ApiConfig apiConfig,
144142
ApiMethodConfig methodConfig,
145143
SystemService systemService,
146144
Object expectedResult,
147145
Object... params) {
148-
super(initParameters, null /* servletContext */, endpointMethod, apiConfig, methodConfig,
146+
super(initParameters, null /* servletContext */, endpointMethod, methodConfig,
149147
systemService);
150148
this.params = params;
151149
this.expectedResult = expectedResult;

0 commit comments

Comments
 (0)