Skip to content

Commit 05b73ce

Browse files
committed
Call getErrorAttributes() only once
Refine the fix introduced in commit 60b7e6c so that the `getErrorAttributes()` method is not called multiple times. If the status is missing, the `DefaultErrorWebExceptionHandler` will now call an internal `DefaultErrorAttributes` instance in order to obtain the actual status result. Fixes gh-41732
1 parent d974686 commit 05b73ce

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

Diff for: spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
3131
import org.springframework.boot.web.error.ErrorAttributeOptions;
3232
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
33+
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
3334
import org.springframework.boot.web.reactive.error.ErrorAttributes;
3435
import org.springframework.context.ApplicationContext;
3536
import org.springframework.http.HttpStatus;
@@ -94,6 +95,8 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
9495

9596
private static final ErrorAttributeOptions ONLY_STATUS = ErrorAttributeOptions.of(Include.STATUS);
9697

98+
private static final DefaultErrorAttributes defaultErrorAttributes = new DefaultErrorAttributes();
99+
97100
private final ErrorProperties errorProperties;
98101

99102
/**
@@ -121,8 +124,8 @@ protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes erro
121124
* @return a {@code Publisher} of the HTTP response
122125
*/
123126
protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
124-
int status = getHttpStatus(getErrorAttributes(request, ONLY_STATUS));
125127
Map<String, Object> errorAttributes = getErrorAttributes(request, MediaType.TEXT_HTML);
128+
int status = getHttpStatus(request, errorAttributes);
126129
ServerResponse.BodyBuilder responseBody = ServerResponse.status(status).contentType(TEXT_HTML_UTF8);
127130
return Flux.just(getData(status).toArray(new String[] {}))
128131
.flatMap((viewName) -> renderErrorView(viewName, responseBody, errorAttributes))
@@ -148,8 +151,8 @@ private List<String> getData(int errorStatus) {
148151
* @return a {@code Publisher} of the HTTP response
149152
*/
150153
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
151-
int status = getHttpStatus(getErrorAttributes(request, ONLY_STATUS));
152154
Map<String, Object> errorAttributes = getErrorAttributes(request, MediaType.ALL);
155+
int status = getHttpStatus(request, errorAttributes);
153156
return ServerResponse.status(status)
154157
.contentType(MediaType.APPLICATION_JSON)
155158
.body(BodyInserters.fromValue(errorAttributes));
@@ -234,6 +237,11 @@ protected boolean isIncludePath(ServerRequest request, MediaType produces) {
234237
};
235238
}
236239

240+
private int getHttpStatus(ServerRequest request, Map<String, Object> errorAttributes) {
241+
return getHttpStatus(errorAttributes.containsKey("status") ? errorAttributes
242+
: defaultErrorAttributes.getErrorAttributes(request, ONLY_STATUS));
243+
}
244+
237245
/**
238246
* Get the HTTP error status information from the error map.
239247
* @param errorAttributes the current error information

Diff for: spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandlerIntegrationTests.java

+36
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.nio.charset.StandardCharsets;
2020
import java.util.HashMap;
21+
import java.util.LinkedHashMap;
2122
import java.util.Map;
2223

2324
import jakarta.validation.Valid;
@@ -597,6 +598,21 @@ void customErrorWebExceptionHandlerWithoutStatus() {
597598
});
598599
}
599600

601+
@Test
602+
void customErrorAttributesWithoutStatus() {
603+
this.contextRunner.withUserConfiguration(CustomErrorAttributesWithoutStatus.class).run((context) -> {
604+
WebTestClient client = getWebClient(context);
605+
client.get()
606+
.uri("/badRequest")
607+
.exchange()
608+
.expectStatus()
609+
.isBadRequest()
610+
.expectBody()
611+
.jsonPath("status")
612+
.doesNotExist();
613+
});
614+
}
615+
600616
private String getErrorTemplatesLocation() {
601617
String packageName = getClass().getPackage().getName();
602618
return "classpath:/" + packageName.replace('.', '/') + "/templates/";
@@ -686,6 +702,7 @@ static class CustomErrorAttributesWithoutDelegation {
686702
@Bean
687703
ErrorAttributes errorAttributes() {
688704
return new DefaultErrorAttributes() {
705+
689706
@Override
690707
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
691708
Map<String, Object> errorAttributes = new HashMap<>();
@@ -724,4 +741,23 @@ protected ErrorAttributeOptions getErrorAttributeOptions(ServerRequest request,
724741

725742
}
726743

744+
@Configuration(proxyBeanMethods = false)
745+
static class CustomErrorAttributesWithoutStatus {
746+
747+
@Bean
748+
ErrorAttributes errorAttributes() {
749+
return new DefaultErrorAttributes() {
750+
751+
@Override
752+
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
753+
Map<String, Object> attributes = new LinkedHashMap<>(super.getErrorAttributes(request, options));
754+
attributes.remove("status");
755+
return attributes;
756+
}
757+
758+
};
759+
}
760+
761+
}
762+
727763
}

0 commit comments

Comments
 (0)