Skip to content

Commit 3c7dbae

Browse files
authored
Merge pull request #691 from awslabs/690-exception-handler
handle Spring's ErrorResponse in separate default ExceptionHandlers
2 parents 040112a + ffd858e commit 3c7dbae

File tree

8 files changed

+99
-10
lines changed

8 files changed

+99
-10
lines changed

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.amazonaws.serverless.proxy.model.Headers;
2020

2121
import com.fasterxml.jackson.core.JsonProcessingException;
22+
import jakarta.ws.rs.core.Response;
2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
2425

@@ -47,22 +48,22 @@ public class AwsProxyExceptionHandler
4748
// Constants
4849
//-------------------------------------------------------------
4950

50-
static final String INTERNAL_SERVER_ERROR = "Internal Server Error";
51-
static final String GATEWAY_TIMEOUT_ERROR = "Gateway timeout";
51+
static final String INTERNAL_SERVER_ERROR = Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase();
52+
static final String GATEWAY_TIMEOUT_ERROR = Response.Status.GATEWAY_TIMEOUT.getReasonPhrase();
5253

5354

5455
//-------------------------------------------------------------
5556
// Variables - Private - Static
5657
//-------------------------------------------------------------
5758

58-
private static Headers headers = new Headers();
59+
protected static final Headers HEADERS = new Headers();
5960

6061
//-------------------------------------------------------------
6162
// Constructors
6263
//-------------------------------------------------------------
6364

6465
static {
65-
headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
66+
HEADERS.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
6667
}
6768

6869

@@ -79,9 +80,9 @@ public AwsProxyResponse handle(Throwable ex) {
7980
// output to go to the stderr.
8081
ex.printStackTrace();
8182
if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) {
82-
return new AwsProxyResponse(500, headers, getErrorJson(INTERNAL_SERVER_ERROR));
83+
return new AwsProxyResponse(500, HEADERS, getErrorJson(INTERNAL_SERVER_ERROR));
8384
} else {
84-
return new AwsProxyResponse(502, headers, getErrorJson(GATEWAY_TIMEOUT_ERROR));
85+
return new AwsProxyResponse(502, HEADERS, getErrorJson(GATEWAY_TIMEOUT_ERROR));
8586
}
8687
}
8788

@@ -98,7 +99,7 @@ public void handle(Throwable ex, OutputStream stream) throws IOException {
9899
// Methods - Protected
99100
//-------------------------------------------------------------
100101

101-
String getErrorJson(String message) {
102+
protected String getErrorJson(String message) {
102103

103104
try {
104105
return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message));

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public Builder defaultProxy() {
9696
.requestReader((RequestReader<RequestType, ContainerRequestType>) new AwsProxyHttpServletRequestReader())
9797
.responseWriter((ResponseWriter<AwsHttpServletResponse, ResponseType>) new AwsProxyHttpServletResponseWriter())
9898
.securityContextWriter((SecurityContextWriter<RequestType>) new AwsProxySecurityContextWriter())
99-
.exceptionHandler((ExceptionHandler<ResponseType>) new AwsProxyExceptionHandler())
99+
.exceptionHandler(defaultExceptionHandler())
100100
.requestTypeClass((Class<RequestType>) AwsProxyRequest.class)
101101
.responseTypeClass((Class<ResponseType>) AwsProxyResponse.class);
102102
return self();
@@ -112,13 +112,17 @@ public Builder defaultHttpApiV2Proxy() {
112112
.requestReader((RequestReader<RequestType, ContainerRequestType>) new AwsHttpApiV2HttpServletRequestReader())
113113
.responseWriter((ResponseWriter<AwsHttpServletResponse, ResponseType>) new AwsProxyHttpServletResponseWriter(true))
114114
.securityContextWriter((SecurityContextWriter<RequestType>) new AwsHttpApiV2SecurityContextWriter())
115-
.exceptionHandler((ExceptionHandler<ResponseType>) new AwsProxyExceptionHandler())
115+
.exceptionHandler(defaultExceptionHandler())
116116
.requestTypeClass((Class<RequestType>) HttpApiV2ProxyRequest.class)
117117
.responseTypeClass((Class<ResponseType>) AwsProxyResponse.class);
118118
return self();
119119

120120
}
121121

122+
protected ExceptionHandler<ResponseType> defaultExceptionHandler() {
123+
return (ExceptionHandler<ResponseType>) new AwsProxyExceptionHandler();
124+
}
125+
122126
/**
123127
* Sets the initialization wrapper to be used by the {@link ServletLambdaContainerHandlerBuilder#buildAndInitialize()}
124128
* method to start the framework implementations

aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ void errorMessage_InternalServerError_staticString() {
231231

232232
@Test
233233
void errorMessage_GatewayTimeout_staticString() {
234-
assertEquals("Gateway timeout", AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR);
234+
assertEquals("Gateway Timeout", AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR);
235235
}
236236

237237
@Test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.amazonaws.serverless.proxy.spring;
2+
3+
import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler;
4+
import com.amazonaws.serverless.proxy.ExceptionHandler;
5+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
6+
import org.springframework.web.ErrorResponse;
7+
8+
/**
9+
* This ExceptionHandler implementation enhances the standard AwsProxyExceptionHandler
10+
* by mapping additional details from org.springframework.web.ErrorResponse
11+
*/
12+
public class SpringAwsProxyExceptionHandler extends AwsProxyExceptionHandler
13+
implements ExceptionHandler<AwsProxyResponse> {
14+
@Override
15+
public AwsProxyResponse handle(Throwable ex) {
16+
if (ex instanceof ErrorResponse) {
17+
return new AwsProxyResponse(((ErrorResponse) ex).getStatusCode().value(),
18+
HEADERS, getErrorJson(ex.getMessage()));
19+
} else {
20+
return super.handle(ex);
21+
}
22+
}
23+
24+
}

aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package com.amazonaws.serverless.proxy.spring;
1414

1515
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
16+
import com.amazonaws.serverless.proxy.ExceptionHandler;
1617
import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder;
1718
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
1819
import org.springframework.web.context.ConfigurableWebApplicationContext;
@@ -86,4 +87,9 @@ public SpringLambdaContainerHandler<RequestType, AwsProxyResponse> buildAndIniti
8687
initializationWrapper.start(handler);
8788
return handler;
8889
}
90+
91+
@Override
92+
protected ExceptionHandler<AwsProxyResponse> defaultExceptionHandler() {
93+
return new SpringAwsProxyExceptionHandler();
94+
}
8995
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.amazonaws.serverless.proxy.spring;
2+
3+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
4+
import jakarta.ws.rs.core.Response;
5+
import org.junit.jupiter.api.Test;
6+
import org.springframework.http.HttpHeaders;
7+
import org.springframework.http.HttpMethod;
8+
import org.springframework.web.servlet.NoHandlerFoundException;
9+
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
12+
public class SpringAwsProxyExceptionHandlerTest {
13+
14+
@Test
15+
void noHandlerFoundExceptionResultsIn404() {
16+
AwsProxyResponse response = new SpringAwsProxyExceptionHandler().
17+
handle(new NoHandlerFoundException(HttpMethod.GET.name(), "https://atesturl",
18+
HttpHeaders.EMPTY));
19+
assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode());
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.amazonaws.serverless.proxy.spring;
2+
3+
import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler;
4+
import com.amazonaws.serverless.proxy.ExceptionHandler;
5+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
6+
import org.springframework.web.ErrorResponse;
7+
8+
/**
9+
* This ExceptionHandler implementation enhances the standard AwsProxyExceptionHandler
10+
* by mapping additional details from org.springframework.web.ErrorResponse
11+
*
12+
* As of now this class is identical with SpringAwsProxyExceptionHandler. We may consider
13+
* moving it to a common module to share it in the future.
14+
*/
15+
public class SpringBootAwsProxyExceptionHandler extends AwsProxyExceptionHandler
16+
implements ExceptionHandler<AwsProxyResponse> {
17+
@Override
18+
public AwsProxyResponse handle(Throwable ex) {
19+
if (ex instanceof ErrorResponse) {
20+
return new AwsProxyResponse(((ErrorResponse) ex).getStatusCode().value(),
21+
HEADERS, getErrorJson(ex.getMessage()));
22+
} else {
23+
return super.handle(ex);
24+
}
25+
}
26+
27+
}

aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package com.amazonaws.serverless.proxy.spring;
1414

1515
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
16+
import com.amazonaws.serverless.proxy.ExceptionHandler;
1617
import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder;
1718
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
1819
import org.springframework.boot.WebApplicationType;
@@ -79,4 +80,9 @@ public SpringBootLambdaContainerHandler<RequestType, AwsProxyResponse> buildAndI
7980
initializationWrapper.start(handler);
8081
return handler;
8182
}
83+
84+
@Override
85+
protected ExceptionHandler<AwsProxyResponse> defaultExceptionHandler() {
86+
return new SpringBootAwsProxyExceptionHandler();
87+
}
8288
}

0 commit comments

Comments
 (0)