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

Commit 03341b9

Browse files
committed
allow null error fields
Currently a NullPointerException is thrown due to disallowed null values in ImmutableMap. This change changes error construction to use Jackson data to allow for null values.
1 parent 4521d4e commit 03341b9

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package com.google.api.server.spi.response;
1717

18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import com.fasterxml.jackson.databind.node.ArrayNode;
20+
import com.fasterxml.jackson.databind.node.ObjectNode;
21+
import com.google.api.server.spi.ObjectMapperUtil;
1822
import com.google.api.server.spi.ServiceException;
1923
import com.google.api.server.spi.config.model.ApiSerializationConfig;
2024
import com.google.common.base.Strings;
@@ -31,12 +35,14 @@
3135
*/
3236
public class RestResponseResultWriter extends ServletResponseResultWriter {
3337
private final boolean enableExceptionCompatibility;
38+
private final ObjectMapper objectMapper;
3439

3540
public RestResponseResultWriter(
3641
HttpServletResponse servletResponse, ApiSerializationConfig serializationConfig,
3742
boolean prettyPrint, boolean enableExceptionCompatibility) {
3843
super(servletResponse, serializationConfig, prettyPrint);
3944
this.enableExceptionCompatibility = enableExceptionCompatibility;
45+
this.objectMapper = ObjectMapperUtil.createStandardObjectMapper(serializationConfig);
4046
}
4147

4248
/**
@@ -69,15 +75,16 @@ public void writeError(ServiceException e) throws IOException {
6975
}
7076

7177
private Object createError(int code, String reason, String domain, String message) {
72-
return ImmutableMap.of(
73-
"error", ImmutableMap.of(
74-
"errors", ImmutableList.of(ImmutableMap.of(
75-
"domain", domain,
76-
"reason", reason,
77-
"message", message
78-
)),
79-
"code", code,
80-
"message", message
81-
));
78+
ObjectNode topLevel = objectMapper.createObjectNode();
79+
ObjectNode topError = objectMapper.createObjectNode();
80+
ObjectNode error = objectMapper.createObjectNode();
81+
error.put("domain", domain);
82+
error.put("reason", reason);
83+
error.put("message", message);
84+
topError.set("errors", objectMapper.createArrayNode().add(error));
85+
topError.put("code", code);
86+
topError.put("message", message);
87+
topLevel.set("error", topError);
88+
return topLevel;
8289
}
8390
}

endpoints-framework/src/test/java/com/google/api/server/spi/response/RestResponseResultWriterTest.java

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public void writeError_401() throws Exception {
4747
@Test
4848
public void writeError_402() throws Exception {
4949
doWriteErrorTest(402 /* exceptionCode */, 404 /* expectedCompatCode */,
50-
"unsupportedProtocol" /* compatReason */, "paymentRequired" /* reason */);
50+
"unsupportedProtocol" /* compatReason */, "paymentRequired" /* reason */,
51+
"error" /* message */);
5152
}
5253

5354
@Test
@@ -68,19 +69,21 @@ public void writeError_405() throws Exception {
6869
@Test
6970
public void writeError_406() throws Exception {
7071
doWriteErrorTest(406 /* exceptionCode */, 404 /* expectedCompatCode */,
71-
"unsupportedProtocol" /* compatReason */, "notAcceptable" /* reason */);
72+
"unsupportedProtocol" /* compatReason */, "notAcceptable" /* reason */,
73+
"error" /* message */);
7274
}
7375

7476
@Test
7577
public void writeError_407() throws Exception {
7678
doWriteErrorTest(407 /* exceptionCode */, 404 /* expectedCompatCode */,
77-
"unsupportedProtocol" /* compatReason */, "proxyAuthentication" /* reason */);
79+
"unsupportedProtocol" /* compatReason */, "proxyAuthentication" /* reason */,
80+
"error" /* message */);
7881
}
7982

8083
@Test
8184
public void writeError_408() throws Exception {
8285
doWriteErrorTest(408 /* exceptionCode */, 503 /* expectedCompatCode */,
83-
"backendError" /* compatReason */, "requestTimeout" /* reason */);
86+
"backendError" /* compatReason */, "requestTimeout" /* reason */, "error" /* message */);
8487
}
8588

8689
@Test
@@ -96,7 +99,8 @@ public void writeError_410() throws Exception {
9699
@Test
97100
public void writeError_411() throws Exception {
98101
doWriteErrorTest(411 /* exceptionCode */, 404 /* expectedCompatCode */,
99-
"unsupportedProtocol" /* compatReason */, "lengthRequired" /* reason */);
102+
"unsupportedProtocol" /* compatReason */, "lengthRequired" /* reason */,
103+
"error" /* message */);
100104
}
101105

102106
@Test
@@ -112,25 +116,25 @@ public void writeError_413() throws Exception {
112116
@Test
113117
public void writeError_414() throws Exception {
114118
doWriteErrorTest(414 /* exceptionCode */, 404 /* expectedCompatCode */,
115-
"unsupportedProtocol" /* compatReason */, "uriTooLong" /* reason */);
119+
"unsupportedProtocol" /* compatReason */, "uriTooLong" /* reason */, "error" /* message */);
116120
}
117121

118122
@Test
119123
public void writeError_415() throws Exception {
120124
doWriteErrorTest(415 /* exceptionCode */, 404 /* expectedCompatCode */,
121-
"unsupportedProtocol" /* compatReason */, "unsupportedMediaType");
125+
"unsupportedProtocol" /* compatReason */, "unsupportedMediaType", "error" /* message */);
122126
}
123127

124128
@Test
125129
public void writeError_416() throws Exception {
126130
doWriteErrorTest(416 /* exceptionCode */, 404 /* expectedCompatCode */,
127-
"unsupportedProtocol" /* compatReason */, "rangeNotSatisfiable");
131+
"unsupportedProtocol" /* compatReason */, "rangeNotSatisfiable", "error" /* message */);
128132
}
129133

130134
@Test
131135
public void writeError_417() throws Exception {
132136
doWriteErrorTest(417 /* exceptionCode */, 404 /* expectedCompatCode */,
133-
"unsupportedProtocol" /* compatReason */, "expectationFailed");
137+
"unsupportedProtocol" /* compatReason */, "expectationFailed", "error" /* message */);
134138
}
135139

136140
@Test
@@ -141,40 +145,54 @@ public void writeError_500s() throws Exception {
141145
}
142146
}
143147

148+
@Test
149+
public void writeError_nullMessage() throws Exception {
150+
doWriteErrorTest(500 /* exceptionCode */, 503 /* expectedCompatCode */,
151+
"backendError" /* compatReason */, "backendError" /* reason */, null);
152+
}
153+
144154
/**
145155
* Tests that an error is translated according to Lily if specified, and the code is left alone
146156
* if compatibility mode is off. Both cases test for the correct error structure in the response.
147157
*/
148158
private void doWriteErrorTest(int exceptionCode, int expectedCompatCode, String reason)
149159
throws Exception {
150-
doWriteErrorTest(exceptionCode, expectedCompatCode, reason, reason);
160+
doWriteErrorTest(exceptionCode, expectedCompatCode, reason, reason, "error");
151161
}
152162

153163
/**
154164
* Tests that an error is translated according to Lily if specified, and the code is left alone
155165
* if compatibility mode is off. Both cases test for the correct error structure in the response.
156166
*/
157167
private void doWriteErrorTest(int exceptionCode, int expectedCompatCode, String compatReason,
158-
String reason) throws Exception {
159-
writeError(exceptionCode, expectedCompatCode, compatReason, true);
160-
writeError(exceptionCode, exceptionCode, reason, false);
168+
String reason, String message) throws Exception {
169+
writeError(exceptionCode, expectedCompatCode, compatReason, message, true);
170+
writeError(exceptionCode, exceptionCode, reason, message, false);
161171
}
162172

163-
private void writeError(int exceptionCode, int expectedCode, String reason,
173+
private void writeError(int exceptionCode, int expectedCode, String reason, String message,
164174
boolean enableExceptionCompatibility) throws Exception {
165175
MockHttpServletResponse response = new MockHttpServletResponse();
166176
RestResponseResultWriter writer = new RestResponseResultWriter(
167177
response, null, true /* prettyPrint */, enableExceptionCompatibility);
168-
writer.writeError(new ServiceException(exceptionCode, "error"));
178+
writer.writeError(new ServiceException(exceptionCode, message));
169179
ObjectMapper mapper = ObjectMapperUtil.createStandardObjectMapper();
170180
ObjectNode content = mapper.readValue(response.getContentAsString(), ObjectNode.class);
171181
JsonNode outerError = content.path("error");
172182
assertThat(outerError.path("code").asInt()).isEqualTo(expectedCode);
173-
assertThat(outerError.path("message").asText()).isEqualTo("error");
183+
if (message == null) {
184+
assertThat(outerError.path("message").isNull()).isTrue();
185+
} else {
186+
assertThat(outerError.path("message").asText()).isEqualTo(message);
187+
}
174188
JsonNode innerError = outerError.path("errors").path(0);
175189
assertThat(innerError.path("domain").asText()).isEqualTo("global");
176190
assertThat(innerError.path("reason").asText()).isEqualTo(reason);
177-
assertThat(innerError.path("message").asText()).isEqualTo("error");
191+
if (message == null) {
192+
assertThat(innerError.path("message").isNull()).isTrue();
193+
} else {
194+
assertThat(innerError.path("message").asText()).isEqualTo(message);
195+
}
178196
}
179197

180198
@Test

0 commit comments

Comments
 (0)