From f6b696323c24798095d641e756f0dc064e619392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20K=C3=BChl?= Date: Wed, 23 Jul 2025 12:24:35 +0200 Subject: [PATCH] Keep headers when mapping ResponseStatusException The default mapping for Spring `ResponseStatusException` in `ResponseStatusAdvice` discards the headers that subclasses can register on the exception. This change adapts `ResponseStatusAdvice` to instead use those headers when creating a `ResponseEntity`. --- .../web/advice/general/ResponseStatusAdviceTrait.java | 2 +- .../spring/web/advice/example/ExampleRestController.java | 8 ++++++++ .../web/advice/general/ResponseStatusAdviceTraitTest.java | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/problem-spring-web/src/main/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTrait.java b/problem-spring-web/src/main/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTrait.java index 89d2448b..ff383714 100644 --- a/problem-spring-web/src/main/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTrait.java +++ b/problem-spring-web/src/main/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTrait.java @@ -25,7 +25,7 @@ default ResponseEntity handleResponseStatusException( final ResponseStatusException exception, final NativeWebRequest request) { String reason = exception.getReason(); - return create(new HttpStatusAdapter(exception.getStatusCode()),exception, request); + return create(new HttpStatusAdapter(exception.getStatusCode()),exception, request, exception.getHeaders()); } } diff --git a/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java b/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java index 893053b3..e2ed8710 100644 --- a/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java +++ b/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java @@ -12,6 +12,7 @@ import dev.failsafe.CircuitBreaker; import dev.failsafe.Failsafe; import lombok.Data; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -112,6 +113,13 @@ private static final class MyResponseStatusException extends ResponseStatusExcep MyResponseStatusException() { super(HttpStatus.NOT_IMPLEMENTED); } + + @Override + public HttpHeaders getHeaders() { + var headers = new HttpHeaders(); + headers.set(HttpHeaders.RETRY_AFTER, "5"); + return headers; + } } @RequestMapping(path = "/nested-throwable", method = GET) diff --git a/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTraitTest.java b/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTraitTest.java index 3d0dfc6f..8ad9442b 100644 --- a/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTraitTest.java +++ b/problem-spring-web/src/test/java/org/zalando/problem/spring/web/advice/general/ResponseStatusAdviceTraitTest.java @@ -17,6 +17,7 @@ void throwableProblem() throws Exception { mvc().perform(request(GET, "http://localhost/api/handler-throwable-extended")) .andExpect(status().isNotImplemented()) .andExpect(header().string("Content-Type", is("application/problem+json"))) + .andExpect(header().string("Retry-After", is("5"))) .andExpect(jsonPath("$.type").doesNotExist()) .andExpect(jsonPath("$.title", is("Not Implemented"))) .andExpect(jsonPath("$.status", is(501)));