Improve null-safety of module/spring-boot-webflux

See gh-46926
This commit is contained in:
Moritz Halbritter
2025-08-26 14:22:56 +02:00
parent 76157c77fa
commit 0d192347fd
4 changed files with 19 additions and 15 deletions
@@ -127,7 +127,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
* @param options options to control error attributes
* @return the error attributes as a Map
*/
protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
protected Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
return this.errorAttributes.getErrorAttributes(request, options);
}
@@ -194,7 +194,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
* @return a Publisher of the {@link ServerResponse}
*/
protected Mono<ServerResponse> renderErrorView(String viewName, ServerResponse.BodyBuilder responseBody,
Map<String, Object> error) {
Map<String, @Nullable Object> error) {
if (isTemplateAvailable(viewName)) {
return responseBody.render(viewName, error);
}
@@ -234,7 +234,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
* @return a Publisher of the {@link ServerResponse}
*/
protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,
Map<String, Object> error) {
Map<String, @Nullable Object> error) {
StringBuilder builder = new StringBuilder();
Date timestamp = (Date) error.get("timestamp");
Object message = error.get("message");
@@ -23,6 +23,7 @@ import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -123,7 +124,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
* @return a {@code Publisher} of the HTTP response
*/
protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
Map<String, Object> errorAttributes = getErrorAttributes(request, MediaType.TEXT_HTML);
Map<String, @Nullable Object> errorAttributes = getErrorAttributes(request, MediaType.TEXT_HTML);
int status = getHttpStatus(request, errorAttributes);
ServerResponse.BodyBuilder responseBody = ServerResponse.status(status).contentType(TEXT_HTML_UTF8);
return Flux.just(getData(status).toArray(new String[] {}))
@@ -150,14 +151,14 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
* @return a {@code Publisher} of the HTTP response
*/
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
Map<String, Object> errorAttributes = getErrorAttributes(request, MediaType.ALL);
Map<String, @Nullable Object> errorAttributes = getErrorAttributes(request, MediaType.ALL);
int status = getHttpStatus(request, errorAttributes);
return ServerResponse.status(status)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(errorAttributes));
}
private Map<String, Object> getErrorAttributes(ServerRequest request, MediaType mediaType) {
private Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, MediaType mediaType) {
return getErrorAttributes(request, getErrorAttributeOptions(request, mediaType));
}
@@ -235,7 +236,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
};
}
private int getHttpStatus(ServerRequest request, Map<String, Object> errorAttributes) {
private int getHttpStatus(ServerRequest request, Map<String, @Nullable Object> errorAttributes) {
return getHttpStatus(errorAttributes.containsKey("status") ? errorAttributes
: defaultErrorAttributes.getErrorAttributes(request, ONLY_STATUS));
}
@@ -245,7 +246,7 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
* @param errorAttributes the current error information
* @return the error HTTP status
*/
protected int getHttpStatus(Map<String, Object> errorAttributes) {
protected int getHttpStatus(Map<String, @Nullable Object> errorAttributes) {
Object status = errorAttributes.get("status");
Assert.state(status instanceof Integer, "ErrorAttributes must contain a status integer");
return (int) status;
@@ -23,6 +23,8 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.web.error.Error;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
@@ -71,14 +73,15 @@ public class DefaultErrorAttributes implements ErrorAttributes {
private static final String ERROR_INTERNAL_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR";
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = getErrorAttributes(request, options.isIncluded(Include.STACK_TRACE));
public Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Map<String, @Nullable Object> errorAttributes = getErrorAttributes(request,
options.isIncluded(Include.STACK_TRACE));
options.retainIncluded(errorAttributes);
return errorAttributes;
}
private Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
private Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Map<String, @Nullable Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
errorAttributes.put("path", request.requestPath().value());
Throwable error = getError(request);
@@ -103,14 +106,14 @@ public class DefaultErrorAttributes implements ErrorAttributes {
return responseStatusAnnotation.getValue("code", HttpStatus.class).orElse(HttpStatus.INTERNAL_SERVER_ERROR);
}
private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) {
private void addStackTrace(Map<String, @Nullable Object> errorAttributes, Throwable error) {
StringWriter stackTrace = new StringWriter();
error.printStackTrace(new PrintWriter(stackTrace));
stackTrace.flush();
errorAttributes.put("trace", stackTrace.toString());
}
private void handleException(Map<String, Object> errorAttributes, Throwable error,
private void handleException(Map<String, @Nullable Object> errorAttributes, Throwable error,
MergedAnnotation<ResponseStatus> responseStatusAnnotation, boolean includeStackTrace) {
Throwable exception;
if (error instanceof BindingResult bindingResult) {
@@ -43,7 +43,7 @@ public interface ErrorAttributes {
* @param options options for error attribute contents
* @return a map of error attributes
*/
default Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
default Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
return Collections.emptyMap();
}