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

See gh-46926
This commit is contained in:
Moritz Halbritter 2025-08-26 09:56:14 +02:00
parent 74320454c9
commit 303d4910bd
5 changed files with 23 additions and 16 deletions

View File

@ -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<String, Object> invoke(ServletWebRequest request) {
public Map<String, @Nullable Object> invoke(ServletWebRequest request) {
return this.errorAttributes.getErrorAttributes(request, getErrorAttributeOptions(request));
}

View File

@ -72,7 +72,8 @@ public abstract class AbstractErrorController implements ErrorController {
return sorted;
}
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, ErrorAttributeOptions options) {
protected Map<String, @Nullable Object> getErrorAttributes(HttpServletRequest request,
ErrorAttributeOptions options) {
WebRequest webRequest = new ServletWebRequest(request);
return this.errorAttributes.getErrorAttributes(webRequest, options);
}

View File

@ -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<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
Map<String, @Nullable Object> body = getErrorAttributes(request,
getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}

View File

@ -93,14 +93,15 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
}
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
public Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, @Nullable Object> errorAttributes = getErrorAttributes(webRequest,
options.isIncluded(Include.STACK_TRACE));
options.retainIncluded(errorAttributes);
return errorAttributes;
}
private Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
private Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, @Nullable Object> 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<String, Object> errorAttributes, RequestAttributes requestAttributes) {
private void addStatus(Map<String, @Nullable Object> 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<String, Object> errorAttributes, WebRequest webRequest,
private void addErrorDetails(Map<String, @Nullable Object> 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<String, Object> errorAttributes, WebRequest webRequest,
private void addErrorMessage(Map<String, @Nullable Object> 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<String, Object> errorAttributes, BindingResult result) {
private void addMessageAndErrorsFromBindingResult(Map<String, @Nullable Object> 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<String, Object> errorAttributes,
private void addMessageAndErrorsFromMethodValidationResult(Map<String, @Nullable Object> 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<String, Object> errorAttributes, WebRequest webRequest,
private void addExceptionErrorMessage(Map<String, @Nullable Object> 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<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 addPath(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {
private void addPath(Map<String, @Nullable Object> errorAttributes, RequestAttributes requestAttributes) {
String path = getAttribute(requestAttributes, RequestDispatcher.ERROR_REQUEST_URI);
if (path != null) {
errorAttributes.put("path", path);

View File

@ -44,7 +44,7 @@ public interface ErrorAttributes {
* @param options options for error attribute contents
* @return a map of error attributes
*/
default Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
default Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
return Collections.emptyMap();
}