From 303d4910bdc042b68cbd48d1d14523d7fbebc445 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 26 Aug 2025 09:56:14 +0200 Subject: [PATCH] Improve null-safety of module/spring-boot-webmvc See gh-46926 --- .../actuate/web/ManagementErrorEndpoint.java | 4 ++- .../error/AbstractErrorController.java | 3 ++- .../error/BasicErrorController.java | 4 ++- .../webmvc/error/DefaultErrorAttributes.java | 26 ++++++++++--------- .../boot/webmvc/error/ErrorAttributes.java | 2 +- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpoint.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpoint.java index b76b627ea14..cff73de1ffc 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpoint.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpoint.java @@ -18,6 +18,8 @@ package org.springframework.boot.webmvc.autoconfigure.actuate.web; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.web.error.ErrorAttributeOptions; import org.springframework.boot.web.error.ErrorAttributeOptions.Include; @@ -55,7 +57,7 @@ public class ManagementErrorEndpoint { @RequestMapping("${server.error.path:${error.path:/error}}") @ResponseBody - public Map invoke(ServletWebRequest request) { + public Map invoke(ServletWebRequest request) { return this.errorAttributes.getErrorAttributes(request, getErrorAttributeOptions(request)); } diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/AbstractErrorController.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/AbstractErrorController.java index 78c37c0c267..99d18feb837 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/AbstractErrorController.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/AbstractErrorController.java @@ -72,7 +72,8 @@ public abstract class AbstractErrorController implements ErrorController { return sorted; } - protected Map getErrorAttributes(HttpServletRequest request, ErrorAttributeOptions options) { + protected Map getErrorAttributes(HttpServletRequest request, + ErrorAttributeOptions options) { WebRequest webRequest = new ServletWebRequest(request); return this.errorAttributes.getErrorAttributes(webRequest, options); } diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorController.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorController.java index 3b600cd3658..e32e92aa794 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorController.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorController.java @@ -22,6 +22,7 @@ import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jspecify.annotations.Nullable; import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.web.error.ErrorAttributeOptions; @@ -99,7 +100,8 @@ public class BasicErrorController extends AbstractErrorController { if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity<>(status); } - Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); + Map body = getErrorAttributes(request, + getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity<>(body, status); } diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/DefaultErrorAttributes.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/DefaultErrorAttributes.java index 9804603d9b2..31009ece332 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/DefaultErrorAttributes.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/DefaultErrorAttributes.java @@ -93,14 +93,15 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException } @Override - public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { - Map errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE)); + public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { + Map errorAttributes = getErrorAttributes(webRequest, + options.isIncluded(Include.STACK_TRACE)); options.retainIncluded(errorAttributes); return errorAttributes; } - private Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { - Map errorAttributes = new LinkedHashMap<>(); + private Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { + Map errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, webRequest); addErrorDetails(errorAttributes, webRequest, includeStackTrace); @@ -108,7 +109,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException return errorAttributes; } - private void addStatus(Map errorAttributes, RequestAttributes requestAttributes) { + private void addStatus(Map errorAttributes, RequestAttributes requestAttributes) { Integer status = getAttribute(requestAttributes, RequestDispatcher.ERROR_STATUS_CODE); if (status == null) { errorAttributes.put("status", 999); @@ -125,7 +126,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException } } - private void addErrorDetails(Map errorAttributes, WebRequest webRequest, + private void addErrorDetails(Map errorAttributes, WebRequest webRequest, boolean includeStackTrace) { Throwable error = getError(webRequest); if (error != null) { @@ -140,7 +141,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException addErrorMessage(errorAttributes, webRequest, error); } - private void addErrorMessage(Map errorAttributes, WebRequest webRequest, + private void addErrorMessage(Map errorAttributes, WebRequest webRequest, @Nullable Throwable error) { BindingResult bindingResult = extractBindingResult(error); if (bindingResult != null) { @@ -155,20 +156,21 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException addExceptionErrorMessage(errorAttributes, webRequest, error); } - private void addMessageAndErrorsFromBindingResult(Map errorAttributes, BindingResult result) { + private void addMessageAndErrorsFromBindingResult(Map errorAttributes, + BindingResult result) { errorAttributes.put("message", "Validation failed for object='%s'. Error count: %s" .formatted(result.getObjectName(), result.getAllErrors().size())); errorAttributes.put("errors", Error.wrapIfNecessary(result.getAllErrors())); } - private void addMessageAndErrorsFromMethodValidationResult(Map errorAttributes, + private void addMessageAndErrorsFromMethodValidationResult(Map errorAttributes, MethodValidationResult result) { errorAttributes.put("message", "Validation failed for method='%s'. Error count: %s" .formatted(result.getMethod(), result.getAllErrors().size())); errorAttributes.put("errors", Error.wrapIfNecessary(result.getAllErrors())); } - private void addExceptionErrorMessage(Map errorAttributes, WebRequest webRequest, + private void addExceptionErrorMessage(Map errorAttributes, WebRequest webRequest, @Nullable Throwable error) { errorAttributes.put("message", getMessage(webRequest, error)); } @@ -211,14 +213,14 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException return null; } - private void addStackTrace(Map errorAttributes, Throwable error) { + private void addStackTrace(Map errorAttributes, Throwable error) { StringWriter stackTrace = new StringWriter(); error.printStackTrace(new PrintWriter(stackTrace)); stackTrace.flush(); errorAttributes.put("trace", stackTrace.toString()); } - private void addPath(Map errorAttributes, RequestAttributes requestAttributes) { + private void addPath(Map errorAttributes, RequestAttributes requestAttributes) { String path = getAttribute(requestAttributes, RequestDispatcher.ERROR_REQUEST_URI); if (path != null) { errorAttributes.put("path", path); diff --git a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorAttributes.java b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorAttributes.java index 9a254af0da5..d617b2bac3f 100644 --- a/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorAttributes.java +++ b/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorAttributes.java @@ -44,7 +44,7 @@ public interface ErrorAttributes { * @param options options for error attribute contents * @return a map of error attributes */ - default Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { + default Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { return Collections.emptyMap(); }