mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-11 04:04:07 +00:00
Add nullability annotations to module/spring-boot-webmvc
See gh-46587
This commit is contained in:
+37
-20
@@ -30,6 +30,7 @@ import java.util.function.Function;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
@@ -58,6 +59,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.ResponseEntity.BodyBuilder;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -96,12 +98,11 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
|
||||
private final EndpointMediaTypes endpointMediaTypes;
|
||||
|
||||
private final CorsConfiguration corsConfiguration;
|
||||
private final @Nullable CorsConfiguration corsConfiguration;
|
||||
|
||||
private final boolean shouldRegisterLinksMapping;
|
||||
|
||||
private final Method handleMethod = ReflectionUtils.findMethod(OperationHandler.class, "handle",
|
||||
HttpServletRequest.class, Map.class);
|
||||
private final Method handleMethod = getHandleMethod();
|
||||
|
||||
private RequestMappingInfo.BuilderConfiguration builderConfig = new RequestMappingInfo.BuilderConfiguration();
|
||||
|
||||
@@ -130,7 +131,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
*/
|
||||
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
|
||||
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
||||
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {
|
||||
@Nullable CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {
|
||||
this.endpointMapping = endpointMapping;
|
||||
this.endpoints = endpoints;
|
||||
this.endpointMediaTypes = endpointMediaTypes;
|
||||
@@ -139,6 +140,13 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
setOrder(-100);
|
||||
}
|
||||
|
||||
private static Method getHandleMethod() {
|
||||
Method method = ReflectionUtils.findMethod(OperationHandler.class, "handle", HttpServletRequest.class,
|
||||
Map.class);
|
||||
Assert.state(method != null, "'method' must not be null");
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
this.builderConfig = new RequestMappingInfo.BuilderConfiguration();
|
||||
@@ -219,8 +227,10 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
.options(this.builderConfig)
|
||||
.build();
|
||||
LinksHandler linksHandler = getLinksHandler();
|
||||
registerMapping(mapping, linksHandler, ReflectionUtils.findMethod(linksHandler.getClass(), "links",
|
||||
HttpServletRequest.class, HttpServletResponse.class));
|
||||
Method links = ReflectionUtils.findMethod(linksHandler.getClass(), "links", HttpServletRequest.class,
|
||||
HttpServletResponse.class);
|
||||
Assert.state(links != null, "'links' must not be null");
|
||||
registerMapping(mapping, linksHandler, links);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,12 +239,13 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mapping) {
|
||||
protected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,
|
||||
RequestMappingInfo mapping) {
|
||||
return this.corsConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
|
||||
protected @Nullable CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
|
||||
CorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, request);
|
||||
return (corsConfiguration != null) ? corsConfiguration : this.corsConfiguration;
|
||||
}
|
||||
@@ -245,7 +256,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
protected @Nullable RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -269,7 +280,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
@FunctionalInterface
|
||||
protected interface LinksHandler {
|
||||
|
||||
Object links(HttpServletRequest request, HttpServletResponse response);
|
||||
@Nullable Object links(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
}
|
||||
|
||||
@@ -279,7 +290,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
@FunctionalInterface
|
||||
protected interface ServletWebOperation {
|
||||
|
||||
Object handle(HttpServletRequest request, Map<String, String> body);
|
||||
@Nullable Object handle(HttpServletRequest request, @Nullable Map<String, String> body);
|
||||
|
||||
}
|
||||
|
||||
@@ -309,7 +320,8 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handle(HttpServletRequest request, @RequestBody(required = false) Map<String, String> body) {
|
||||
public @Nullable Object handle(HttpServletRequest request,
|
||||
@RequestBody(required = false) @Nullable Map<String, String> body) {
|
||||
HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
|
||||
Map<String, Object> arguments = getArguments(request, body);
|
||||
try {
|
||||
@@ -341,7 +353,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
return "Actuator web endpoint '" + this.operation.getId() + "'";
|
||||
}
|
||||
|
||||
private Map<String, Object> getArguments(HttpServletRequest request, Map<String, String> body) {
|
||||
private Map<String, Object> getArguments(HttpServletRequest request, @Nullable Map<String, String> body) {
|
||||
Map<String, Object> arguments = new LinkedHashMap<>(getTemplateVariables(request));
|
||||
String matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()
|
||||
.getMatchAllRemainingPathSegmentsVariable();
|
||||
@@ -386,7 +398,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
return (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private Object handleResult(Object result, HttpMethod httpMethod) {
|
||||
private @Nullable Object handleResult(@Nullable Object result, HttpMethod httpMethod) {
|
||||
if (result == null) {
|
||||
return new ResponseEntity<>(
|
||||
(httpMethod != HttpMethod.GET) ? HttpStatus.NO_CONTENT : HttpStatus.NOT_FOUND);
|
||||
@@ -396,12 +408,17 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
}
|
||||
MediaType contentType = (response.getContentType() != null) ? new MediaType(response.getContentType())
|
||||
: null;
|
||||
return ResponseEntity.status(response.getStatus())
|
||||
.contentType(contentType)
|
||||
.body(convertIfNecessary(response.getBody()));
|
||||
BodyBuilder builder = ResponseEntity.status(response.getStatus());
|
||||
if (contentType != null) {
|
||||
builder = builder.contentType(contentType);
|
||||
}
|
||||
return builder.body(convertIfNecessary(response.getBody()));
|
||||
}
|
||||
|
||||
private Object convertIfNecessary(Object body) {
|
||||
private @Nullable Object convertIfNecessary(@Nullable Object body) {
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
for (Function<Object, Object> converter : BODY_CONVERTERS) {
|
||||
body = converter.apply(body);
|
||||
}
|
||||
@@ -435,7 +452,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
|
||||
@ResponseBody
|
||||
@Reflective
|
||||
Object handle(HttpServletRequest request, @RequestBody(required = false) Map<String, String> body) {
|
||||
@Nullable Object handle(HttpServletRequest request, @RequestBody(required = false) Map<String, String> body) {
|
||||
return this.operation.handle(request, body);
|
||||
}
|
||||
|
||||
@@ -504,7 +521,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
||||
private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
this.reflectiveRegistrar.registerRuntimeHints(hints, OperationHandler.class);
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -20,7 +20,10 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
|
||||
@@ -37,18 +40,18 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
*/
|
||||
public class AdditionalHealthEndpointPathsWebMvcHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {
|
||||
|
||||
private final ExposableWebEndpoint healthEndpoint;
|
||||
private final @Nullable ExposableWebEndpoint healthEndpoint;
|
||||
|
||||
private final Set<HealthEndpointGroup> groups;
|
||||
|
||||
public AdditionalHealthEndpointPathsWebMvcHandlerMapping(ExposableWebEndpoint healthEndpoint,
|
||||
public AdditionalHealthEndpointPathsWebMvcHandlerMapping(@Nullable ExposableWebEndpoint healthEndpoint,
|
||||
Set<HealthEndpointGroup> groups) {
|
||||
super(new EndpointMapping(""), asList(healthEndpoint), null, false);
|
||||
super(new EndpointMapping(""), asList(healthEndpoint), new EndpointMediaTypes(), false);
|
||||
this.healthEndpoint = healthEndpoint;
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
private static Collection<ExposableWebEndpoint> asList(ExposableWebEndpoint healthEndpoint) {
|
||||
private static Collection<ExposableWebEndpoint> asList(@Nullable ExposableWebEndpoint healthEndpoint) {
|
||||
return (healthEndpoint != null) ? Collections.singletonList(healthEndpoint) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -73,7 +76,7 @@ public class AdditionalHealthEndpointPathsWebMvcHandlerMapping extends AbstractW
|
||||
|
||||
@Override
|
||||
protected LinksHandler getLinksHandler() {
|
||||
return null;
|
||||
return (request, response) -> null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-6
@@ -25,6 +25,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Access;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
@@ -34,9 +36,11 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
/**
|
||||
* {@link HandlerMapping} that exposes
|
||||
@@ -58,7 +62,7 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
|
||||
private final EndpointMapping endpointMapping;
|
||||
|
||||
private final CorsConfiguration corsConfiguration;
|
||||
private final @Nullable CorsConfiguration corsConfiguration;
|
||||
|
||||
private final Map<Object, ExposableControllerEndpoint> handlers;
|
||||
|
||||
@@ -72,7 +76,7 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
* @param corsConfiguration the CORS configuration for the endpoints or {@code null}
|
||||
*/
|
||||
public ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,
|
||||
Collection<ExposableControllerEndpoint> endpoints, CorsConfiguration corsConfiguration) {
|
||||
Collection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration) {
|
||||
this(endpointMapping, endpoints, corsConfiguration, (endpointId, defaultAccess) -> Access.NONE);
|
||||
}
|
||||
|
||||
@@ -85,7 +89,7 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
* @param endpointAccessResolver resolver for endpoint access
|
||||
*/
|
||||
public ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,
|
||||
Collection<ExposableControllerEndpoint> endpoints, CorsConfiguration corsConfiguration,
|
||||
Collection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration,
|
||||
EndpointAccessResolver endpointAccessResolver) {
|
||||
Assert.notNull(endpointMapping, "'endpointMapping' must not be null");
|
||||
Assert.notNull(endpoints, "'endpoints' must not be null");
|
||||
@@ -110,6 +114,7 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
@Override
|
||||
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
|
||||
ExposableControllerEndpoint endpoint = this.handlers.get(handler);
|
||||
Assert.state(endpoint != null, "'endpoint' must not be null");
|
||||
Access access = this.accessResolver.accessFor(endpoint.getEndpointId(), endpoint.getDefaultAccess());
|
||||
if (access == Access.NONE) {
|
||||
return;
|
||||
@@ -138,9 +143,13 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
|
||||
private RequestMappingInfo withEndpointMappedPatterns(ExposableControllerEndpoint endpoint,
|
||||
RequestMappingInfo mapping) {
|
||||
Set<PathPattern> patterns = mapping.getPathPatternsCondition().getPatterns();
|
||||
PathPatternsRequestCondition condition = mapping.getPathPatternsCondition();
|
||||
Assert.state(condition != null, "'condition' must not be null");
|
||||
Set<PathPattern> patterns = condition.getPatterns();
|
||||
if (patterns.isEmpty()) {
|
||||
patterns = Collections.singleton(getPatternParser().parse(""));
|
||||
PathPatternParser parser = getPatternParser();
|
||||
Assert.state(parser != null, "'parser' must not be null");
|
||||
patterns = Collections.singleton(parser.parse(""));
|
||||
}
|
||||
String[] endpointMappedPatterns = patterns.stream()
|
||||
.map((pattern) -> getEndpointMappedPattern(endpoint, pattern))
|
||||
@@ -158,7 +167,8 @@ public class ControllerEndpointHandlerMapping extends RequestMappingHandlerMappi
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mapping) {
|
||||
protected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,
|
||||
RequestMappingInfo mapping) {
|
||||
return this.corsConfiguration;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -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.aot.hint.BindingReflectionHintsRegistrar;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
@@ -64,7 +65,7 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM
|
||||
* @param shouldRegisterLinksMapping whether the links endpoint should be registered
|
||||
*/
|
||||
public WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<ExposableWebEndpoint> endpoints,
|
||||
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
|
||||
EndpointMediaTypes endpointMediaTypes, @Nullable CorsConfiguration corsConfiguration,
|
||||
EndpointLinksResolver linksResolver, boolean shouldRegisterLinksMapping) {
|
||||
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping);
|
||||
this.linksResolver = linksResolver;
|
||||
@@ -104,7 +105,7 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM
|
||||
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
this.reflectiveRegistrar.registerRuntimeHints(hints, WebMvcLinksHandler.class);
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Spring MVC support for actuator endpoints.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.actuate.endpoint.web;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+5
-1
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.undertow.servlet.api.DeploymentManager;
|
||||
import jakarta.servlet.ServletException;
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Context;
|
||||
@@ -133,7 +134,10 @@ final class DispatcherServletHandlerMappings {
|
||||
|
||||
void initializeServlet(String name) {
|
||||
try {
|
||||
this.webServer.getDeploymentManager().getDeployment().getServlets().getManagedServlet(name).forceInit();
|
||||
DeploymentManager deploymentManager = this.webServer.getDeploymentManager();
|
||||
if (deploymentManager != null) {
|
||||
deploymentManager.getDeployment().getServlets().getManagedServlet(name).forceInit();
|
||||
}
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
// Continue
|
||||
|
||||
+6
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.webmvc.actuate.mappings;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
@@ -30,9 +32,10 @@ public class DispatcherServletMappingDescription {
|
||||
|
||||
private final String predicate;
|
||||
|
||||
private final DispatcherServletMappingDetails details;
|
||||
private final @Nullable DispatcherServletMappingDetails details;
|
||||
|
||||
DispatcherServletMappingDescription(String predicate, String handler, DispatcherServletMappingDetails details) {
|
||||
DispatcherServletMappingDescription(String predicate, String handler,
|
||||
@Nullable DispatcherServletMappingDetails details) {
|
||||
this.handler = handler;
|
||||
this.predicate = predicate;
|
||||
this.details = details;
|
||||
@@ -46,7 +49,7 @@ public class DispatcherServletMappingDescription {
|
||||
return this.predicate;
|
||||
}
|
||||
|
||||
public DispatcherServletMappingDetails getDetails() {
|
||||
public @Nullable DispatcherServletMappingDetails getDetails() {
|
||||
return this.details;
|
||||
}
|
||||
|
||||
|
||||
+11
-9
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.webmvc.actuate.mappings;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
@@ -28,33 +30,33 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
*/
|
||||
public class DispatcherServletMappingDetails {
|
||||
|
||||
private HandlerMethodDescription handlerMethod;
|
||||
private @Nullable HandlerMethodDescription handlerMethod;
|
||||
|
||||
private HandlerFunctionDescription handlerFunction;
|
||||
private @Nullable HandlerFunctionDescription handlerFunction;
|
||||
|
||||
private RequestMappingConditionsDescription requestMappingConditions;
|
||||
private @Nullable RequestMappingConditionsDescription requestMappingConditions;
|
||||
|
||||
public HandlerMethodDescription getHandlerMethod() {
|
||||
public @Nullable HandlerMethodDescription getHandlerMethod() {
|
||||
return this.handlerMethod;
|
||||
}
|
||||
|
||||
void setHandlerMethod(HandlerMethodDescription handlerMethod) {
|
||||
void setHandlerMethod(@Nullable HandlerMethodDescription handlerMethod) {
|
||||
this.handlerMethod = handlerMethod;
|
||||
}
|
||||
|
||||
public HandlerFunctionDescription getHandlerFunction() {
|
||||
public @Nullable HandlerFunctionDescription getHandlerFunction() {
|
||||
return this.handlerFunction;
|
||||
}
|
||||
|
||||
void setHandlerFunction(HandlerFunctionDescription handlerFunction) {
|
||||
void setHandlerFunction(@Nullable HandlerFunctionDescription handlerFunction) {
|
||||
this.handlerFunction = handlerFunction;
|
||||
}
|
||||
|
||||
public RequestMappingConditionsDescription getRequestMappingConditions() {
|
||||
public @Nullable RequestMappingConditionsDescription getRequestMappingConditions() {
|
||||
return this.requestMappingConditions;
|
||||
}
|
||||
|
||||
void setRequestMappingConditions(RequestMappingConditionsDescription requestMappingConditions) {
|
||||
void setRequestMappingConditions(@Nullable RequestMappingConditionsDescription requestMappingConditions) {
|
||||
this.requestMappingConditions = requestMappingConditions;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -28,6 +28,7 @@ import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
@@ -272,7 +273,7 @@ public class DispatcherServletsMappingDescriptionProvider implements MappingDesc
|
||||
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(),
|
||||
DispatcherServletMappingDescription.class);
|
||||
}
|
||||
|
||||
+12
-4
@@ -19,9 +19,13 @@ package org.springframework.boot.webmvc.actuate.mappings;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.condition.MediaTypeExpression;
|
||||
import org.springframework.web.servlet.mvc.condition.NameValueExpression;
|
||||
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
|
||||
/**
|
||||
@@ -73,8 +77,12 @@ public class RequestMappingConditionsDescription {
|
||||
private Set<String> extractPathPatterns(RequestMappingInfo requestMapping) {
|
||||
org.springframework.web.servlet.mvc.condition.PatternsRequestCondition patternsCondition = requestMapping
|
||||
.getPatternsCondition();
|
||||
return (patternsCondition != null) ? patternsCondition.getPatterns()
|
||||
: requestMapping.getPathPatternsCondition().getPatternValues();
|
||||
if (patternsCondition != null) {
|
||||
return patternsCondition.getPatterns();
|
||||
}
|
||||
PathPatternsRequestCondition condition = requestMapping.getPathPatternsCondition();
|
||||
Assert.state(condition != null, "'condition' must not be null");
|
||||
return condition.getPatternValues();
|
||||
}
|
||||
|
||||
public List<MediaTypeExpressionDescription> getConsumes() {
|
||||
@@ -132,7 +140,7 @@ public class RequestMappingConditionsDescription {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Object value;
|
||||
private final @Nullable Object value;
|
||||
|
||||
private final boolean negated;
|
||||
|
||||
@@ -146,7 +154,7 @@ public class RequestMappingConditionsDescription {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
public @Nullable Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Actuator request mappings support for Spring MVC.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.actuate.mappings;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -47,6 +47,7 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.multipart.MultipartResolver;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
@@ -132,6 +133,7 @@ public final class DispatcherServletAutoConfiguration {
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Default DispatcherServlet");
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
Assert.state(beanFactory != null, "'beanFactory' must not be null");
|
||||
List<String> dispatchServletBeans = Arrays
|
||||
.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
|
||||
if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
|
||||
@@ -158,6 +160,7 @@ public final class DispatcherServletAutoConfiguration {
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
Assert.state(beanFactory != null, "'beanFactory' must not be null");
|
||||
ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);
|
||||
if (!outcome.isMatch()) {
|
||||
return outcome;
|
||||
|
||||
+33
-15
@@ -18,6 +18,7 @@ package org.springframework.boot.webmvc.autoconfigure;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -25,6 +26,7 @@ import jakarta.servlet.Servlet;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
@@ -74,9 +76,12 @@ import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
@@ -201,9 +206,9 @@ public final class WebMvcAutoConfiguration {
|
||||
|
||||
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
|
||||
|
||||
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
|
||||
private final @Nullable ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
|
||||
|
||||
private ServletContext servletContext;
|
||||
private @Nullable ServletContext servletContext;
|
||||
|
||||
private final ObjectProvider<ApiVersionResolver> apiVersionResolvers;
|
||||
|
||||
@@ -328,7 +333,7 @@ public final class WebMvcAutoConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageCodesResolver getMessageCodesResolver() {
|
||||
public @Nullable MessageCodesResolver getMessageCodesResolver() {
|
||||
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
|
||||
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
|
||||
resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
|
||||
@@ -370,13 +375,20 @@ public final class WebMvcAutoConfiguration {
|
||||
}
|
||||
ResourceHandlerRegistration registration = registry.addResourceHandler(pattern);
|
||||
customizer.accept(registration);
|
||||
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
|
||||
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
|
||||
Integer cachePeriod = getSeconds(this.resourceProperties.getCache().getPeriod());
|
||||
if (cachePeriod != null) {
|
||||
registration.setCachePeriod(cachePeriod);
|
||||
}
|
||||
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
|
||||
if (cacheControl != null) {
|
||||
registration.setCacheControl(cacheControl);
|
||||
}
|
||||
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
|
||||
customizeResourceHandlerRegistration(registration);
|
||||
}
|
||||
|
||||
private Integer getSeconds(Duration cachePeriod) {
|
||||
@Contract("!null -> !null")
|
||||
private @Nullable Integer getSeconds(@Nullable Duration cachePeriod) {
|
||||
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
|
||||
}
|
||||
|
||||
@@ -433,8 +445,9 @@ public final class WebMvcAutoConfiguration {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final WebMvcRegistrations mvcRegistrations;
|
||||
private final @Nullable WebMvcRegistrations mvcRegistrations;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
EnableWebMvcConfiguration(WebMvcProperties mvcProperties, WebProperties webProperties,
|
||||
@@ -491,11 +504,13 @@ public final class WebMvcAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
|
||||
public LocaleResolver localeResolver() {
|
||||
Locale locale = this.webProperties.getLocale();
|
||||
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
|
||||
return new FixedLocaleResolver(this.webProperties.getLocale());
|
||||
Assert.state(locale != null, "'locale' must not be null");
|
||||
return new FixedLocaleResolver(locale);
|
||||
}
|
||||
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
|
||||
localeResolver.setDefaultLocale(this.webProperties.getLocale());
|
||||
localeResolver.setDefaultLocale(locale);
|
||||
return localeResolver;
|
||||
}
|
||||
|
||||
@@ -513,7 +528,7 @@ public final class WebMvcAutoConfiguration {
|
||||
return super.viewNameTranslator();
|
||||
}
|
||||
|
||||
private Resource getIndexHtmlResource() {
|
||||
private @Nullable Resource getIndexHtmlResource() {
|
||||
for (String location : this.resourceProperties.getStaticLocations()) {
|
||||
Resource indexHtml = getIndexHtmlResource(location);
|
||||
if (indexHtml != null) {
|
||||
@@ -527,11 +542,11 @@ public final class WebMvcAutoConfiguration {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Resource getIndexHtmlResource(String location) {
|
||||
private @Nullable Resource getIndexHtmlResource(String location) {
|
||||
return getIndexHtmlResource(this.resourceLoader.getResource(location));
|
||||
}
|
||||
|
||||
private Resource getIndexHtmlResource(Resource location) {
|
||||
private @Nullable Resource getIndexHtmlResource(Resource location) {
|
||||
try {
|
||||
Resource resource = location.createRelative("index.html");
|
||||
if (resource.exists() && (resource.getURL() != null)) {
|
||||
@@ -564,7 +579,9 @@ public final class WebMvcAutoConfiguration {
|
||||
getClass().getClassLoader())) {
|
||||
return super.mvcValidator();
|
||||
}
|
||||
return ValidatorAdapter.get(getApplicationContext(), getValidator());
|
||||
ApplicationContext applicationContext = getApplicationContext();
|
||||
Assert.state(applicationContext != null, "'applicationContext' must not be null");
|
||||
return ValidatorAdapter.get(applicationContext, getValidator());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -620,7 +637,7 @@ public final class WebMvcAutoConfiguration {
|
||||
|
||||
@Override
|
||||
@ConditionalOnMissingBean(name = "mvcApiVersionStrategy")
|
||||
public ApiVersionStrategy mvcApiVersionStrategy() {
|
||||
public @Nullable ApiVersionStrategy mvcApiVersionStrategy() {
|
||||
return super.mvcApiVersionStrategy();
|
||||
}
|
||||
|
||||
@@ -642,7 +659,7 @@ public final class WebMvcAutoConfiguration {
|
||||
interface WelcomePageHandlerMappingFactory<T extends AbstractUrlHandlerMapping> {
|
||||
|
||||
T create(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext,
|
||||
Resource indexHtmlResource, String staticPathPattern);
|
||||
@Nullable Resource indexHtmlResource, String staticPathPattern);
|
||||
|
||||
}
|
||||
|
||||
@@ -682,6 +699,7 @@ public final class WebMvcAutoConfiguration {
|
||||
if (properties.getFixed().isEnabled()) {
|
||||
String version = properties.getFixed().getVersion();
|
||||
String[] paths = properties.getFixed().getPaths();
|
||||
Assert.state(version != null, "'version' must not be null");
|
||||
resolver.addFixedVersionStrategy(version, paths);
|
||||
}
|
||||
if (properties.getContent().isEnabled()) {
|
||||
|
||||
+47
-45
@@ -22,6 +22,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.Name;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -45,7 +47,7 @@ public class WebMvcProperties {
|
||||
/**
|
||||
* Formatting strategy for message codes. For instance, 'PREFIX_ERROR_CODE'.
|
||||
*/
|
||||
private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
|
||||
private DefaultMessageCodesResolver.@Nullable Format messageCodesResolverFormat;
|
||||
|
||||
private final Format format = new Format();
|
||||
|
||||
@@ -100,11 +102,11 @@ public class WebMvcProperties {
|
||||
|
||||
private final Apiversion apiversion = new Apiversion();
|
||||
|
||||
public DefaultMessageCodesResolver.Format getMessageCodesResolverFormat() {
|
||||
public DefaultMessageCodesResolver.@Nullable Format getMessageCodesResolverFormat() {
|
||||
return this.messageCodesResolverFormat;
|
||||
}
|
||||
|
||||
public void setMessageCodesResolverFormat(DefaultMessageCodesResolver.Format messageCodesResolverFormat) {
|
||||
public void setMessageCodesResolverFormat(DefaultMessageCodesResolver.@Nullable Format messageCodesResolverFormat) {
|
||||
this.messageCodesResolverFormat = messageCodesResolverFormat;
|
||||
}
|
||||
|
||||
@@ -202,13 +204,13 @@ public class WebMvcProperties {
|
||||
* Amount of time before asynchronous request handling times out. If this value is
|
||||
* not set, the default timeout of the underlying implementation is used.
|
||||
*/
|
||||
private Duration requestTimeout;
|
||||
private @Nullable Duration requestTimeout;
|
||||
|
||||
public Duration getRequestTimeout() {
|
||||
public @Nullable Duration getRequestTimeout() {
|
||||
return this.requestTimeout;
|
||||
}
|
||||
|
||||
public void setRequestTimeout(Duration requestTimeout) {
|
||||
public void setRequestTimeout(@Nullable Duration requestTimeout) {
|
||||
this.requestTimeout = requestTimeout;
|
||||
}
|
||||
|
||||
@@ -282,26 +284,26 @@ public class WebMvcProperties {
|
||||
/**
|
||||
* Spring MVC view prefix.
|
||||
*/
|
||||
private String prefix;
|
||||
private @Nullable String prefix;
|
||||
|
||||
/**
|
||||
* Spring MVC view suffix.
|
||||
*/
|
||||
private String suffix;
|
||||
private @Nullable String suffix;
|
||||
|
||||
public String getPrefix() {
|
||||
public @Nullable String getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
public void setPrefix(@Nullable String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public String getSuffix() {
|
||||
public @Nullable String getSuffix() {
|
||||
return this.suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(String suffix) {
|
||||
public void setSuffix(@Nullable String suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
@@ -318,7 +320,7 @@ public class WebMvcProperties {
|
||||
/**
|
||||
* Query parameter name to use when "favor-parameter" is enabled.
|
||||
*/
|
||||
private String parameterName;
|
||||
private @Nullable String parameterName;
|
||||
|
||||
/**
|
||||
* Map file extensions to media types for content negotiation. For instance, yml
|
||||
@@ -340,11 +342,11 @@ public class WebMvcProperties {
|
||||
this.favorParameter = favorParameter;
|
||||
}
|
||||
|
||||
public String getParameterName() {
|
||||
public @Nullable String getParameterName() {
|
||||
return this.parameterName;
|
||||
}
|
||||
|
||||
public void setParameterName(String parameterName) {
|
||||
public void setParameterName(@Nullable String parameterName) {
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
|
||||
@@ -389,41 +391,41 @@ public class WebMvcProperties {
|
||||
* Date format to use, for example 'dd/MM/yyyy'. Used for formatting of
|
||||
* java.util.Date and java.time.LocalDate.
|
||||
*/
|
||||
private String date;
|
||||
private @Nullable String date;
|
||||
|
||||
/**
|
||||
* Time format to use, for example 'HH:mm:ss'. Used for formatting of java.time's
|
||||
* LocalTime and OffsetTime.
|
||||
*/
|
||||
private String time;
|
||||
private @Nullable String time;
|
||||
|
||||
/**
|
||||
* Date-time format to use, for example 'yyyy-MM-dd HH:mm:ss'. Used for formatting
|
||||
* of java.time's LocalDateTime, OffsetDateTime, and ZonedDateTime.
|
||||
*/
|
||||
private String dateTime;
|
||||
private @Nullable String dateTime;
|
||||
|
||||
public String getDate() {
|
||||
public @Nullable String getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
public void setDate(@Nullable String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
public @Nullable String getTime() {
|
||||
return this.time;
|
||||
}
|
||||
|
||||
public void setTime(String time) {
|
||||
public void setTime(@Nullable String time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getDateTime() {
|
||||
public @Nullable String getDateTime() {
|
||||
return this.dateTime;
|
||||
}
|
||||
|
||||
public void setDateTime(String dateTime) {
|
||||
public void setDateTime(@Nullable String dateTime) {
|
||||
this.dateTime = dateTime;
|
||||
}
|
||||
|
||||
@@ -477,58 +479,58 @@ public class WebMvcProperties {
|
||||
/**
|
||||
* Whether the API version is required with each request.
|
||||
*/
|
||||
private Boolean required;
|
||||
private @Nullable Boolean required;
|
||||
|
||||
/**
|
||||
* Default version that should be used for each request.
|
||||
*/
|
||||
@Name("default")
|
||||
private String defaultVersion;
|
||||
private @Nullable String defaultVersion;
|
||||
|
||||
/**
|
||||
* Supported versions.
|
||||
*/
|
||||
private List<String> supported;
|
||||
private @Nullable List<String> supported;
|
||||
|
||||
/**
|
||||
* Whether supported versions should be detected from controllers.
|
||||
*/
|
||||
private Boolean detectSupported;
|
||||
private @Nullable Boolean detectSupported;
|
||||
|
||||
/**
|
||||
* How version details should be inserted into requests.
|
||||
*/
|
||||
private final Use use = new Use();
|
||||
|
||||
public Boolean getRequired() {
|
||||
public @Nullable Boolean getRequired() {
|
||||
return this.required;
|
||||
}
|
||||
|
||||
public void setRequired(Boolean required) {
|
||||
public void setRequired(@Nullable Boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public String getDefaultVersion() {
|
||||
public @Nullable String getDefaultVersion() {
|
||||
return this.defaultVersion;
|
||||
}
|
||||
|
||||
public void setDefaultVersion(String defaultVersion) {
|
||||
public void setDefaultVersion(@Nullable String defaultVersion) {
|
||||
this.defaultVersion = defaultVersion;
|
||||
}
|
||||
|
||||
public List<String> getSupported() {
|
||||
public @Nullable List<String> getSupported() {
|
||||
return this.supported;
|
||||
}
|
||||
|
||||
public void setSupported(List<String> supported) {
|
||||
public void setSupported(@Nullable List<String> supported) {
|
||||
this.supported = supported;
|
||||
}
|
||||
|
||||
public Boolean getDetectSupported() {
|
||||
public @Nullable Boolean getDetectSupported() {
|
||||
return this.detectSupported;
|
||||
}
|
||||
|
||||
public void setDetectSupported(Boolean detectSupported) {
|
||||
public void setDetectSupported(@Nullable Boolean detectSupported) {
|
||||
this.detectSupported = detectSupported;
|
||||
}
|
||||
|
||||
@@ -541,44 +543,44 @@ public class WebMvcProperties {
|
||||
/**
|
||||
* Use the HTTP header with the given name to obtain the version.
|
||||
*/
|
||||
private String header;
|
||||
private @Nullable String header;
|
||||
|
||||
/**
|
||||
* Use the query parameter with the given name to obtain the version.
|
||||
*/
|
||||
private String queryParameter;
|
||||
private @Nullable String queryParameter;
|
||||
|
||||
/**
|
||||
* Use the path segment at the given index to obtain the version.
|
||||
*/
|
||||
private Integer pathSegment;
|
||||
private @Nullable Integer pathSegment;
|
||||
|
||||
/**
|
||||
* Use the media type parameter with the given name to obtain the version.
|
||||
*/
|
||||
private Map<MediaType, String> mediaTypeParameter = new LinkedHashMap<>();
|
||||
|
||||
public String getHeader() {
|
||||
public @Nullable String getHeader() {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
public void setHeader(String header) {
|
||||
public void setHeader(@Nullable String header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public String getQueryParameter() {
|
||||
public @Nullable String getQueryParameter() {
|
||||
return this.queryParameter;
|
||||
}
|
||||
|
||||
public void setQueryParameter(String queryParameter) {
|
||||
public void setQueryParameter(@Nullable String queryParameter) {
|
||||
this.queryParameter = queryParameter;
|
||||
}
|
||||
|
||||
public Integer getPathSegment() {
|
||||
public @Nullable Integer getPathSegment() {
|
||||
return this.pathSegment;
|
||||
}
|
||||
|
||||
public void setPathSegment(Integer pathSegment) {
|
||||
public void setPathSegment(@Nullable Integer pathSegment) {
|
||||
this.pathSegment = pathSegment;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.webmvc.autoconfigure;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
@@ -44,7 +46,7 @@ public interface WebMvcRegistrations {
|
||||
* processed by the MVC configuration.
|
||||
* @return the custom {@link RequestMappingHandlerMapping} instance
|
||||
*/
|
||||
default RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
|
||||
default @Nullable RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ public interface WebMvcRegistrations {
|
||||
* processed by the MVC configuration.
|
||||
* @return the custom {@link RequestMappingHandlerAdapter} instance
|
||||
*/
|
||||
default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
|
||||
default @Nullable RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -62,7 +64,7 @@ public interface WebMvcRegistrations {
|
||||
* processed by the MVC configuration.
|
||||
* @return the custom {@link ExceptionHandlerExceptionResolver} instance
|
||||
*/
|
||||
default ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
|
||||
default @Nullable ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.webmvc.autoconfigure;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -32,11 +34,11 @@ final class WelcomePage {
|
||||
*/
|
||||
static final WelcomePage UNRESOLVED = new WelcomePage(null, false);
|
||||
|
||||
private final String viewName;
|
||||
private final @Nullable String viewName;
|
||||
|
||||
private final boolean templated;
|
||||
|
||||
private WelcomePage(String viewName, boolean templated) {
|
||||
private WelcomePage(@Nullable String viewName, boolean templated) {
|
||||
this.viewName = viewName;
|
||||
this.templated = templated;
|
||||
}
|
||||
@@ -45,7 +47,7 @@ final class WelcomePage {
|
||||
* Return the view name of the welcome page.
|
||||
* @return the view name
|
||||
*/
|
||||
String getViewName() {
|
||||
@Nullable String getViewName() {
|
||||
return this.viewName;
|
||||
}
|
||||
|
||||
@@ -66,7 +68,7 @@ final class WelcomePage {
|
||||
* @return a resolved {@link WelcomePage} instance or {@link #UNRESOLVED}
|
||||
*/
|
||||
static WelcomePage resolve(TemplateAvailabilityProviders templateAvailabilityProviders,
|
||||
ApplicationContext applicationContext, Resource indexHtmlResource, String staticPathPattern) {
|
||||
ApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {
|
||||
if (indexHtmlResource != null && "/**".equals(staticPathPattern)) {
|
||||
return new WelcomePage("forward:index.html", false);
|
||||
}
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -51,7 +52,7 @@ final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
|
||||
private static final List<MediaType> MEDIA_TYPES_ALL = Collections.singletonList(MediaType.ALL);
|
||||
|
||||
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
|
||||
ApplicationContext applicationContext, Resource indexHtmlResource, String staticPathPattern) {
|
||||
ApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {
|
||||
setOrder(2);
|
||||
WelcomePage welcomePage = WelcomePage.resolve(templateAvailabilityProviders, applicationContext,
|
||||
indexHtmlResource, staticPathPattern);
|
||||
@@ -65,7 +66,7 @@ final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
public @Nullable Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
return (!isHtmlTextAccepted(request)) ? null : super.getHandlerInternal(request);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -18,6 +18,7 @@ package org.springframework.boot.webmvc.autoconfigure;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -36,7 +37,7 @@ import org.springframework.web.servlet.mvc.Controller;
|
||||
class WelcomePageNotAcceptableHandlerMapping extends AbstractUrlHandlerMapping {
|
||||
|
||||
WelcomePageNotAcceptableHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
|
||||
ApplicationContext applicationContext, Resource indexHtmlResource, String staticPathPattern) {
|
||||
ApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {
|
||||
setOrder(LOWEST_PRECEDENCE - 10); // Before ResourceHandlerRegistry
|
||||
WelcomePage welcomePage = WelcomePage.resolve(templateAvailabilityProviders, applicationContext,
|
||||
indexHtmlResource, staticPathPattern);
|
||||
@@ -45,13 +46,13 @@ class WelcomePageNotAcceptableHandlerMapping extends AbstractUrlHandlerMapping {
|
||||
}
|
||||
}
|
||||
|
||||
private ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
private @Nullable ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
response.setStatus(HttpStatus.NOT_ACCEPTABLE.value());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
protected @Nullable Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||
return super.getHandlerInternal(request);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
@@ -56,7 +58,7 @@ public final class WebMvcHealthEndpointExtensionAutoConfiguration {
|
||||
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
|
||||
}
|
||||
|
||||
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
|
||||
private static @Nullable ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
return webEndpoints.stream()
|
||||
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Spring MVC actuator web endpoint support.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ import java.util.Optional;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
@@ -39,7 +40,7 @@ class CompositeHandlerAdapter implements HandlerAdapter {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private List<HandlerAdapter> adapters;
|
||||
private @Nullable List<HandlerAdapter> adapters;
|
||||
|
||||
CompositeHandlerAdapter(ListableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
@@ -51,7 +52,7 @@ class CompositeHandlerAdapter implements HandlerAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
public @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
Optional<HandlerAdapter> adapter = getAdapter(handler);
|
||||
if (adapter.isPresent()) {
|
||||
|
||||
+5
-4
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
@@ -46,11 +47,11 @@ class CompositeHandlerExceptionResolver implements HandlerExceptionResolver {
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private volatile List<HandlerExceptionResolver> resolvers;
|
||||
private volatile @Nullable List<HandlerExceptionResolver> resolvers;
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
public @Nullable ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
|
||||
@Nullable Object handler, Exception ex) {
|
||||
for (HandlerExceptionResolver resolver : getResolvers()) {
|
||||
ModelAndView resolved = resolver.resolveException(request, response, handler, ex);
|
||||
if (resolved != null) {
|
||||
@@ -76,7 +77,7 @@ class CompositeHandlerExceptionResolver implements HandlerExceptionResolver {
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
private void collectResolverBeans(List<HandlerExceptionResolver> resolvers, BeanFactory beanFactory) {
|
||||
private void collectResolverBeans(List<HandlerExceptionResolver> resolvers, @Nullable BeanFactory beanFactory) {
|
||||
if (beanFactory instanceof ListableBeanFactory listableBeanFactory) {
|
||||
resolvers.addAll(listableBeanFactory.getBeansOfType(HandlerExceptionResolver.class).values());
|
||||
}
|
||||
|
||||
+3
-2
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -39,10 +40,10 @@ class CompositeHandlerMapping implements HandlerMapping {
|
||||
@Autowired
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private List<HandlerMapping> mappings;
|
||||
private @Nullable List<HandlerMapping> mappings;
|
||||
|
||||
@Override
|
||||
public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
|
||||
public @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
|
||||
for (HandlerMapping mapping : getMappings()) {
|
||||
HandlerExecutionChain handler = mapping.getHandler(request);
|
||||
if (handler != null) {
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Spring MVC-based actuator infrastructure.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.autoconfigure.actuate.web;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+6
-4
@@ -23,6 +23,7 @@ import java.util.Map;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.boot.webmvc.error.ErrorAttributes;
|
||||
@@ -55,13 +56,14 @@ public abstract class AbstractErrorController implements ErrorController {
|
||||
this(errorAttributes, null);
|
||||
}
|
||||
|
||||
public AbstractErrorController(ErrorAttributes errorAttributes, List<ErrorViewResolver> errorViewResolvers) {
|
||||
public AbstractErrorController(ErrorAttributes errorAttributes,
|
||||
@Nullable List<ErrorViewResolver> errorViewResolvers) {
|
||||
Assert.notNull(errorAttributes, "'errorAttributes' must not be null");
|
||||
this.errorAttributes = errorAttributes;
|
||||
this.errorViewResolvers = sortErrorViewResolvers(errorViewResolvers);
|
||||
}
|
||||
|
||||
private List<ErrorViewResolver> sortErrorViewResolvers(List<ErrorViewResolver> resolvers) {
|
||||
private List<ErrorViewResolver> sortErrorViewResolvers(@Nullable List<ErrorViewResolver> resolvers) {
|
||||
List<ErrorViewResolver> sorted = new ArrayList<>();
|
||||
if (resolvers != null) {
|
||||
sorted.addAll(resolvers);
|
||||
@@ -142,8 +144,8 @@ public abstract class AbstractErrorController implements ErrorController {
|
||||
* @return a specific {@link ModelAndView} or {@code null} if the default should be
|
||||
* used
|
||||
*/
|
||||
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,
|
||||
Map<String, Object> model) {
|
||||
protected @Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response,
|
||||
HttpStatus status, Map<String, Object> model) {
|
||||
for (ErrorViewResolver resolver : this.errorViewResolvers) {
|
||||
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
|
||||
if (modelAndView != null) {
|
||||
|
||||
+6
-4
@@ -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.template.TemplateAvailabilityProvider;
|
||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||
@@ -97,7 +98,8 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
|
||||
public @Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
|
||||
Map<String, Object> model) {
|
||||
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
|
||||
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
|
||||
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
|
||||
@@ -105,7 +107,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
private ModelAndView resolve(String viewName, Map<String, Object> model) {
|
||||
private @Nullable ModelAndView resolve(String viewName, Map<String, Object> model) {
|
||||
String errorViewName = "error/" + viewName;
|
||||
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
|
||||
this.applicationContext);
|
||||
@@ -115,7 +117,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||
return resolveResource(errorViewName, model);
|
||||
}
|
||||
|
||||
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
|
||||
private @Nullable ModelAndView resolveResource(String viewName, Map<String, Object> model) {
|
||||
for (String location : this.resources.getStaticLocations()) {
|
||||
try {
|
||||
Resource resource = this.applicationContext.getResource(location);
|
||||
@@ -157,7 +159,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
|
||||
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
response.setContentType(getContentType());
|
||||
FileCopyUtils.copy(this.resource.getInputStream(), response.getOutputStream());
|
||||
|
||||
+11
-4
@@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -65,6 +66,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.view.BeanNameViewResolver;
|
||||
@@ -173,9 +176,11 @@ public final class ErrorMvcAutoConfiguration {
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("ErrorTemplate Missing");
|
||||
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(context.getClassLoader());
|
||||
ClassLoader classLoader = context.getClassLoader();
|
||||
Assert.state(classLoader != null, "'classLoader' must not be null");
|
||||
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(classLoader);
|
||||
TemplateAvailabilityProvider provider = providers.getProvider("error", context.getEnvironment(),
|
||||
context.getClassLoader(), context.getResourceLoader());
|
||||
classLoader, context.getResourceLoader());
|
||||
if (provider != null) {
|
||||
return ConditionOutcome.noMatch(message.foundExactly("template from " + provider));
|
||||
}
|
||||
@@ -194,8 +199,9 @@ public final class ErrorMvcAutoConfiguration {
|
||||
private static final Log logger = LogFactory.getLog(StaticView.class);
|
||||
|
||||
@Override
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
|
||||
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
Assert.state(model != null, "'model' must not be null");
|
||||
if (response.isCommitted()) {
|
||||
String message = getMessage(model);
|
||||
logger.error(message);
|
||||
@@ -229,7 +235,8 @@ public final class ErrorMvcAutoConfiguration {
|
||||
response.getWriter().append(builder.toString());
|
||||
}
|
||||
|
||||
private String htmlEscape(Object input) {
|
||||
@Contract("!null -> !null")
|
||||
private @Nullable String htmlEscape(@Nullable Object input) {
|
||||
return (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ package org.springframework.boot.webmvc.autoconfigure.error;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -39,6 +40,6 @@ public interface ErrorViewResolver {
|
||||
* @param model the suggested model to be used with the view
|
||||
* @return a resolved {@link ModelAndView} or {@code null}
|
||||
*/
|
||||
ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model);
|
||||
@Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model);
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Spring MVC error handling.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.autoconfigure.error;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Spring MVC.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.autoconfigure;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+12
-9
@@ -26,6 +26,7 @@ import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.web.error.Error;
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
@@ -81,8 +82,8 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
Exception ex) {
|
||||
public @Nullable ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
|
||||
@Nullable Object handler, Exception ex) {
|
||||
storeErrorAttributes(request, ex);
|
||||
return null;
|
||||
}
|
||||
@@ -139,7 +140,8 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
addErrorMessage(errorAttributes, webRequest, error);
|
||||
}
|
||||
|
||||
private void addErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {
|
||||
private void addErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest,
|
||||
@Nullable Throwable error) {
|
||||
BindingResult bindingResult = extractBindingResult(error);
|
||||
if (bindingResult != null) {
|
||||
addMessageAndErrorsFromBindingResult(errorAttributes, bindingResult);
|
||||
@@ -166,7 +168,8 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
errorAttributes.put("errors", Error.wrapIfNecessary(result.getAllErrors()));
|
||||
}
|
||||
|
||||
private void addExceptionErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {
|
||||
private void addExceptionErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest,
|
||||
@Nullable Throwable error) {
|
||||
errorAttributes.put("message", getMessage(webRequest, error));
|
||||
}
|
||||
|
||||
@@ -183,7 +186,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
* @param error current error, if any
|
||||
* @return message to include in the error attributes
|
||||
*/
|
||||
protected String getMessage(WebRequest webRequest, Throwable error) {
|
||||
protected String getMessage(WebRequest webRequest, @Nullable Throwable error) {
|
||||
Object message = getAttribute(webRequest, RequestDispatcher.ERROR_MESSAGE);
|
||||
if (!ObjectUtils.isEmpty(message)) {
|
||||
return message.toString();
|
||||
@@ -194,14 +197,14 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
return "No message available";
|
||||
}
|
||||
|
||||
private BindingResult extractBindingResult(Throwable error) {
|
||||
private @Nullable BindingResult extractBindingResult(@Nullable Throwable error) {
|
||||
if (error instanceof BindingResult bindingResult) {
|
||||
return bindingResult;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MethodValidationResult extractMethodValidationResult(Throwable error) {
|
||||
private @Nullable MethodValidationResult extractMethodValidationResult(@Nullable Throwable error) {
|
||||
if (error instanceof MethodValidationResult methodValidationResult) {
|
||||
return methodValidationResult;
|
||||
}
|
||||
@@ -223,7 +226,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getError(WebRequest webRequest) {
|
||||
public @Nullable Throwable getError(WebRequest webRequest) {
|
||||
Throwable exception = getAttribute(webRequest, ERROR_INTERNAL_ATTRIBUTE);
|
||||
if (exception == null) {
|
||||
exception = getAttribute(webRequest, RequestDispatcher.ERROR_EXCEPTION);
|
||||
@@ -232,7 +235,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getAttribute(RequestAttributes requestAttributes, String name) {
|
||||
private <T> @Nullable T getAttribute(RequestAttributes requestAttributes, String name) {
|
||||
return (T) requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ package org.springframework.boot.webmvc.error;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.web.error.ErrorAttributeOptions;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
@@ -52,6 +54,6 @@ public interface ErrorAttributes {
|
||||
* @param webRequest the source request
|
||||
* @return the {@link Exception} that caused the error or {@code null}
|
||||
*/
|
||||
Throwable getError(WebRequest webRequest);
|
||||
@Nullable Throwable getError(WebRequest webRequest);
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Spring MVC error handling infrastructure.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.webmvc.error;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
Reference in New Issue
Block a user