diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java index 1e30f1415..0ae00b4da 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java @@ -19,6 +19,7 @@ import com.amazonaws.serverless.proxy.model.Headers; import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,22 +48,22 @@ public class AwsProxyExceptionHandler // Constants //------------------------------------------------------------- - static final String INTERNAL_SERVER_ERROR = "Internal Server Error"; - static final String GATEWAY_TIMEOUT_ERROR = "Gateway timeout"; + static final String INTERNAL_SERVER_ERROR = Response.Status.INTERNAL_SERVER_ERROR.getReasonPhrase(); + static final String GATEWAY_TIMEOUT_ERROR = Response.Status.GATEWAY_TIMEOUT.getReasonPhrase(); //------------------------------------------------------------- // Variables - Private - Static //------------------------------------------------------------- - private static Headers headers = new Headers(); + protected static final Headers HEADERS = new Headers(); //------------------------------------------------------------- // Constructors //------------------------------------------------------------- static { - headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); + HEADERS.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); } @@ -79,9 +80,9 @@ public AwsProxyResponse handle(Throwable ex) { // output to go to the stderr. ex.printStackTrace(); if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) { - return new AwsProxyResponse(500, headers, getErrorJson(INTERNAL_SERVER_ERROR)); + return new AwsProxyResponse(500, HEADERS, getErrorJson(INTERNAL_SERVER_ERROR)); } else { - return new AwsProxyResponse(502, headers, getErrorJson(GATEWAY_TIMEOUT_ERROR)); + return new AwsProxyResponse(502, HEADERS, getErrorJson(GATEWAY_TIMEOUT_ERROR)); } } @@ -98,7 +99,7 @@ public void handle(Throwable ex, OutputStream stream) throws IOException { // Methods - Protected //------------------------------------------------------------- - String getErrorJson(String message) { + protected String getErrorJson(String message) { try { return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message)); diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java index adacd2e1f..a2c1c73ff 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ServletLambdaContainerHandlerBuilder.java @@ -96,7 +96,7 @@ public Builder defaultProxy() { .requestReader((RequestReader) new AwsProxyHttpServletRequestReader()) .responseWriter((ResponseWriter) new AwsProxyHttpServletResponseWriter()) .securityContextWriter((SecurityContextWriter) new AwsProxySecurityContextWriter()) - .exceptionHandler((ExceptionHandler) new AwsProxyExceptionHandler()) + .exceptionHandler(defaultExceptionHandler()) .requestTypeClass((Class) AwsProxyRequest.class) .responseTypeClass((Class) AwsProxyResponse.class); return self(); @@ -112,13 +112,17 @@ public Builder defaultHttpApiV2Proxy() { .requestReader((RequestReader) new AwsHttpApiV2HttpServletRequestReader()) .responseWriter((ResponseWriter) new AwsProxyHttpServletResponseWriter(true)) .securityContextWriter((SecurityContextWriter) new AwsHttpApiV2SecurityContextWriter()) - .exceptionHandler((ExceptionHandler) new AwsProxyExceptionHandler()) + .exceptionHandler(defaultExceptionHandler()) .requestTypeClass((Class) HttpApiV2ProxyRequest.class) .responseTypeClass((Class) AwsProxyResponse.class); return self(); } + protected ExceptionHandler defaultExceptionHandler() { + return (ExceptionHandler) new AwsProxyExceptionHandler(); + } + /** * Sets the initialization wrapper to be used by the {@link ServletLambdaContainerHandlerBuilder#buildAndInitialize()} * method to start the framework implementations diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java index f94371d69..012827e40 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java @@ -231,7 +231,7 @@ void errorMessage_InternalServerError_staticString() { @Test void errorMessage_GatewayTimeout_staticString() { - assertEquals("Gateway timeout", AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR); + assertEquals("Gateway Timeout", AwsProxyExceptionHandler.GATEWAY_TIMEOUT_ERROR); } @Test diff --git a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandler.java b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandler.java new file mode 100644 index 000000000..21ec94166 --- /dev/null +++ b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandler.java @@ -0,0 +1,24 @@ +package com.amazonaws.serverless.proxy.spring; + +import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler; +import com.amazonaws.serverless.proxy.ExceptionHandler; +import com.amazonaws.serverless.proxy.model.AwsProxyResponse; +import org.springframework.web.ErrorResponse; + +/** + * This ExceptionHandler implementation enhances the standard AwsProxyExceptionHandler + * by mapping additional details from org.springframework.web.ErrorResponse + */ +public class SpringAwsProxyExceptionHandler extends AwsProxyExceptionHandler + implements ExceptionHandler { + @Override + public AwsProxyResponse handle(Throwable ex) { + if (ex instanceof ErrorResponse) { + return new AwsProxyResponse(((ErrorResponse) ex).getStatusCode().value(), + HEADERS, getErrorJson(ex.getMessage())); + } else { + return super.handle(ex); + } + } + +} diff --git a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java index 5614b94df..ba6cbba33 100644 --- a/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java +++ b/aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringProxyHandlerBuilder.java @@ -13,6 +13,7 @@ package com.amazonaws.serverless.proxy.spring; import com.amazonaws.serverless.exceptions.ContainerInitializationException; +import com.amazonaws.serverless.proxy.ExceptionHandler; import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder; import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import org.springframework.web.context.ConfigurableWebApplicationContext; @@ -86,4 +87,9 @@ public SpringLambdaContainerHandler buildAndIniti initializationWrapper.start(handler); return handler; } + + @Override + protected ExceptionHandler defaultExceptionHandler() { + return new SpringAwsProxyExceptionHandler(); + } } diff --git a/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandlerTest.java b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandlerTest.java new file mode 100644 index 000000000..5f4a14152 --- /dev/null +++ b/aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/SpringAwsProxyExceptionHandlerTest.java @@ -0,0 +1,21 @@ +package com.amazonaws.serverless.proxy.spring; + +import com.amazonaws.serverless.proxy.model.AwsProxyResponse; +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.NoHandlerFoundException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SpringAwsProxyExceptionHandlerTest { + + @Test + void noHandlerFoundExceptionResultsIn404() { + AwsProxyResponse response = new SpringAwsProxyExceptionHandler(). + handle(new NoHandlerFoundException(HttpMethod.GET.name(), "https://atesturl", + HttpHeaders.EMPTY)); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode()); + } +} diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootAwsProxyExceptionHandler.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootAwsProxyExceptionHandler.java new file mode 100644 index 000000000..127ef6684 --- /dev/null +++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootAwsProxyExceptionHandler.java @@ -0,0 +1,27 @@ +package com.amazonaws.serverless.proxy.spring; + +import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler; +import com.amazonaws.serverless.proxy.ExceptionHandler; +import com.amazonaws.serverless.proxy.model.AwsProxyResponse; +import org.springframework.web.ErrorResponse; + +/** + * This ExceptionHandler implementation enhances the standard AwsProxyExceptionHandler + * by mapping additional details from org.springframework.web.ErrorResponse + * + * As of now this class is identical with SpringAwsProxyExceptionHandler. We may consider + * moving it to a common module to share it in the future. + */ +public class SpringBootAwsProxyExceptionHandler extends AwsProxyExceptionHandler + implements ExceptionHandler { + @Override + public AwsProxyResponse handle(Throwable ex) { + if (ex instanceof ErrorResponse) { + return new AwsProxyResponse(((ErrorResponse) ex).getStatusCode().value(), + HEADERS, getErrorJson(ex.getMessage())); + } else { + return super.handle(ex); + } + } + +} diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java index cdec18551..e7ad017f1 100644 --- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java +++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootProxyHandlerBuilder.java @@ -13,6 +13,7 @@ package com.amazonaws.serverless.proxy.spring; import com.amazonaws.serverless.exceptions.ContainerInitializationException; +import com.amazonaws.serverless.proxy.ExceptionHandler; import com.amazonaws.serverless.proxy.internal.servlet.ServletLambdaContainerHandlerBuilder; import com.amazonaws.serverless.proxy.model.AwsProxyResponse; import org.springframework.boot.WebApplicationType; @@ -79,4 +80,9 @@ public SpringBootLambdaContainerHandler buildAndI initializationWrapper.start(handler); return handler; } + + @Override + protected ExceptionHandler defaultExceptionHandler() { + return new SpringBootAwsProxyExceptionHandler(); + } }