Switch to JSpecify annotations

This commit updates the whole Spring Framework codebase to use JSpecify
annotations instead of Spring null-safety annotations with JSR 305
semantics.

JSpecify provides signficant enhancements such as properly defined
specifications, a canonical dependency with no split-package issue,
better tooling, better Kotlin integration and the capability to specify
generic type, array and varargs element null-safety. Generic type
null-safety is not defined by this commit yet and will be specified
later.

A key difference is that Spring null-safety annotations, following
JSR 305 semantics, apply to fields, parameters and return values,
while JSpecify annotations apply to type usages. That's why this
commit moves nullability annotations closer to the type for fields
and return values.

See gh-28797
This commit is contained in:
Sébastien Deleuze
2024-12-03 15:22:37 +01:00
parent fcb8aed03f
commit bc5d771a06
3459 changed files with 14118 additions and 22059 deletions

View File

@@ -21,10 +21,11 @@ import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.testfixture.http.MockHttpOutputMessage;
import org.springframework.web.util.UriComponentsBuilder;
@@ -43,13 +44,11 @@ public class MockClientHttpRequest extends MockHttpOutputMessage implements Clie
private URI uri;
@Nullable
private ClientHttpResponse clientHttpResponse;
private @Nullable ClientHttpResponse clientHttpResponse;
private boolean executed = false;
@Nullable
Map<String, Object> attributes;
@Nullable Map<String, Object> attributes;
/**

View File

@@ -1,9 +1,7 @@
/**
* Contains mock request and response types for the imperative HTTP client
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.web.testfixture.http.client;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,9 +1,7 @@
/**
* Contains mock request and response types for the reactive HTTP client
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.web.testfixture.http.client.reactive;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -38,7 +39,6 @@ import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.AbstractServerHttpRequest;
import org.springframework.http.server.reactive.SslInfo;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MimeType;
@@ -57,14 +57,11 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final MultiValueMap<String, HttpCookie> cookies;
@Nullable
private final InetSocketAddress localAddress;
private final @Nullable InetSocketAddress localAddress;
@Nullable
private final InetSocketAddress remoteAddress;
private final @Nullable InetSocketAddress remoteAddress;
@Nullable
private final SslInfo sslInfo;
private final @Nullable SslInfo sslInfo;
private final Flux<DataBuffer> body;
@@ -83,20 +80,17 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
@Override
@Nullable
public InetSocketAddress getLocalAddress() {
public @Nullable InetSocketAddress getLocalAddress() {
return this.localAddress;
}
@Override
@Nullable
public InetSocketAddress getRemoteAddress() {
public @Nullable InetSocketAddress getRemoteAddress() {
return this.remoteAddress;
}
@Override
@Nullable
protected SslInfo initSslInfo() {
protected @Nullable SslInfo initSslInfo() {
return this.sslInfo;
}
@@ -422,8 +416,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final URI url;
@Nullable
private String contextPath;
private @Nullable String contextPath;
private final UriComponentsBuilder queryParamsBuilder = UriComponentsBuilder.newInstance();
@@ -431,14 +424,11 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();
@Nullable
private InetSocketAddress remoteAddress;
private @Nullable InetSocketAddress remoteAddress;
@Nullable
private InetSocketAddress localAddress;
private @Nullable InetSocketAddress localAddress;
@Nullable
private SslInfo sslInfo;
private @Nullable SslInfo sslInfo;
DefaultBodyBuilder(HttpMethod method, URI url) {
this.method = method;

View File

@@ -1,9 +1,7 @@
/**
* For @NonNull annotations on implementation classes
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.web.testfixture.http.server.reactive;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -32,6 +32,7 @@ import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.cglib.core.SpringNamingPolicy;
import org.springframework.cglib.proxy.Callback;
@@ -47,7 +48,6 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.objenesis.ObjenesisException;
import org.springframework.objenesis.SpringObjenesis;
import org.springframework.util.Assert;
@@ -617,12 +617,10 @@ public class ResolvableMethod {
private static class MethodInvocationInterceptor implements MethodInterceptor, InvocationHandler {
@Nullable
private Method invokedMethod;
private @Nullable Method invokedMethod;
@Override
@Nullable
public Object intercept(Object object, Method method, @Nullable Object[] args, @Nullable MethodProxy proxy) {
public @Nullable Object intercept(Object object, Method method, Object @Nullable [] args, @Nullable MethodProxy proxy) {
if (ReflectionUtils.isObjectMethod(method)) {
return ReflectionUtils.invokeMethod(method, object, args);
}
@@ -633,13 +631,11 @@ public class ResolvableMethod {
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) {
public @Nullable Object invoke(Object proxy, Method method, Object @Nullable [] args) {
return intercept(proxy, method, args, null);
}
@Nullable
Method getInvokedMethod() {
@Nullable Method getInvokedMethod() {
return this.invokedMethod;
}
}

View File

@@ -16,10 +16,10 @@
package org.springframework.web.testfixture.server;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Mono;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.web.server.WebSession;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;
@@ -99,8 +99,7 @@ public final class MockServerWebExchange extends DefaultServerWebExchange {
private final MockServerHttpRequest request;
@Nullable
private WebSessionManager sessionManager;
private @Nullable WebSessionManager sessionManager;
public Builder(MockServerHttpRequest request) {

View File

@@ -21,9 +21,9 @@ import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Mono;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.server.WebSession;
import org.springframework.web.server.session.InMemoryWebSessionStore;

View File

@@ -1,9 +1,7 @@
/**
* For @NonNull annotations on implementation classes
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.web.testfixture.server;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -21,7 +21,8 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.CollectionUtils;
/**
@@ -63,13 +64,11 @@ class HeaderValueHolder {
return this.values.stream().map(Object::toString).toList();
}
@Nullable
Object getValue() {
@Nullable Object getValue() {
return (!this.values.isEmpty() ? this.values.get(0) : null);
}
@Nullable
String getStringValue() {
@Nullable String getStringValue() {
return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null);
}

View File

@@ -29,9 +29,9 @@ import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.util.WebUtils;
@@ -45,13 +45,11 @@ public class MockAsyncContext implements AsyncContext {
private final HttpServletRequest request;
@Nullable
private final HttpServletResponse response;
private final @Nullable HttpServletResponse response;
private final List<AsyncListener> listeners = new ArrayList<>();
@Nullable
private String dispatchedPath;
private @Nullable String dispatchedPath;
private long timeout = 10 * 1000L;
@@ -82,8 +80,7 @@ public class MockAsyncContext implements AsyncContext {
}
@Override
@Nullable
public ServletResponse getResponse() {
public @Nullable ServletResponse getResponse() {
return this.response;
}
@@ -110,8 +107,7 @@ public class MockAsyncContext implements AsyncContext {
}
}
@Nullable
public String getDispatchedPath() {
public @Nullable String getDispatchedPath() {
return this.dispatchedPath;
}

View File

@@ -24,8 +24,7 @@ import java.io.Writer;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.jsp.JspWriter;
import jakarta.servlet.jsp.tagext.BodyContent;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Mock implementation of the {@link jakarta.servlet.jsp.tagext.BodyContent} class.

View File

@@ -21,9 +21,9 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import jakarta.servlet.http.Cookie;
import org.jspecify.annotations.Nullable;
import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -54,8 +54,7 @@ public class MockCookie extends Cookie {
private static final String EXPIRES = "Expires";
@Nullable
private ZonedDateTime expires;
private @Nullable ZonedDateTime expires;
/**
@@ -81,8 +80,7 @@ public class MockCookie extends Cookie {
* @return the "Expires" attribute for this cookie, or {@code null} if not set
* @since 5.1.11
*/
@Nullable
public ZonedDateTime getExpires() {
public @Nullable ZonedDateTime getExpires() {
return this.expires;
}
@@ -101,8 +99,7 @@ public class MockCookie extends Cookie {
* Get the "SameSite" attribute for this cookie.
* @return the "SameSite" attribute for this cookie, or {@code null} if not set
*/
@Nullable
public String getSameSite() {
public @Nullable String getSameSite() {
return getAttribute(SAME_SITE);
}

View File

@@ -28,8 +28,8 @@ import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -50,16 +50,13 @@ import org.springframework.util.ObjectUtils;
*/
public class MockFilterChain implements FilterChain {
@Nullable
private ServletRequest request;
private @Nullable ServletRequest request;
@Nullable
private ServletResponse response;
private @Nullable ServletResponse response;
private final List<Filter> filters;
@Nullable
private Iterator<Filter> iterator;
private @Nullable Iterator<Filter> iterator;
/**
@@ -100,16 +97,14 @@ public class MockFilterChain implements FilterChain {
/**
* Return the request that {@link #doFilter} has been called with.
*/
@Nullable
public ServletRequest getRequest() {
public @Nullable ServletRequest getRequest() {
return this.request;
}
/**
* Return the response that {@link #doFilter} has been called with.
*/
@Nullable
public ServletResponse getResponse() {
public @Nullable ServletResponse getResponse() {
return this.response;
}

View File

@@ -23,8 +23,8 @@ import java.util.Map;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletContext;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -29,8 +29,7 @@ import java.util.Set;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterRegistration;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Mock implementation of {@link FilterRegistration}.
@@ -68,9 +67,8 @@ public class MockFilterRegistration implements FilterRegistration.Dynamic {
return this.name;
}
@Nullable
@Override
public String getClassName() {
public @Nullable String getClassName() {
return this.className;
}
@@ -79,9 +77,8 @@ public class MockFilterRegistration implements FilterRegistration.Dynamic {
return (this.initParameters.putIfAbsent(name, value) != null);
}
@Nullable
@Override
public String getInitParameter(String name) {
public @Nullable String getInitParameter(String name) {
return this.initParameters.get(name);
}

View File

@@ -18,8 +18,7 @@ package org.springframework.web.testfixture.servlet;
import jakarta.servlet.http.HttpServletMapping;
import jakarta.servlet.http.MappingMatch;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Mock implementation of {@link HttpServletMapping}.
@@ -35,8 +34,7 @@ public class MockHttpServletMapping implements HttpServletMapping {
private final String servletName;
@Nullable
private final MappingMatch mappingMatch;
private final @Nullable MappingMatch mappingMatch;
public MockHttpServletMapping(
@@ -65,8 +63,7 @@ public class MockHttpServletMapping implements HttpServletMapping {
}
@Override
@Nullable
public MappingMatch getMappingMatch() {
public @Nullable MappingMatch getMappingMatch() {
return this.mappingMatch;
}

View File

@@ -62,10 +62,10 @@ import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpUpgradeHandler;
import jakarta.servlet.http.MappingMatch;
import jakarta.servlet.http.Part;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.LinkedMultiValueMap;
@@ -170,20 +170,15 @@ public class MockHttpServletRequest implements HttpServletRequest {
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Nullable
private String characterEncoding;
private @Nullable String characterEncoding;
@Nullable
private byte[] content;
private byte @Nullable [] content;
@Nullable
private String contentType;
private @Nullable String contentType;
@Nullable
private ServletInputStream inputStream;
private @Nullable ServletInputStream inputStream;
@Nullable
private BufferedReader reader;
private @Nullable BufferedReader reader;
private final Map<String, String[]> parameters = new LinkedHashMap<>(16);
@@ -216,8 +211,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private boolean asyncSupported = false;
@Nullable
private MockAsyncContext asyncContext;
private @Nullable MockAsyncContext asyncContext;
private DispatcherType dispatcherType = DispatcherType.REQUEST;
@@ -226,46 +220,35 @@ public class MockHttpServletRequest implements HttpServletRequest {
// HttpServletRequest properties
// ---------------------------------------------------------------------
@Nullable
private String authType;
private @Nullable String authType;
@Nullable
private Cookie[] cookies;
private @Nullable Cookie[] cookies;
private final Map<String, HeaderValueHolder> headers = new LinkedCaseInsensitiveMap<>();
@Nullable
private String method;
private @Nullable String method;
@Nullable
private String pathInfo;
private @Nullable String pathInfo;
private String contextPath = "";
@Nullable
private String queryString;
private @Nullable String queryString;
@Nullable
private String remoteUser;
private @Nullable String remoteUser;
private final Set<String> userRoles = new HashSet<>();
@Nullable
private Principal userPrincipal;
private @Nullable Principal userPrincipal;
@Nullable
private String requestedSessionId;
private @Nullable String requestedSessionId;
@Nullable
private String uriTemplate;
private @Nullable String uriTemplate;
@Nullable
private String requestURI;
private @Nullable String requestURI;
private String servletPath = "";
@Nullable
private HttpSession session;
private @Nullable HttpSession session;
private boolean requestedSessionIdValid = true;
@@ -275,8 +258,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();
@Nullable
private HttpServletMapping httpServletMapping;
private @Nullable HttpServletMapping httpServletMapping;
// ---------------------------------------------------------------------
@@ -385,8 +367,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
// ---------------------------------------------------------------------
@Override
@Nullable
public Object getAttribute(String name) {
public @Nullable Object getAttribute(String name) {
checkActive();
return this.attributes.get(name);
}
@@ -398,8 +379,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getCharacterEncoding() {
public @Nullable String getCharacterEncoding() {
return this.characterEncoding;
}
@@ -428,7 +408,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
* @see #getContentAsByteArray()
* @see #getContentAsString()
*/
public void setContent(@Nullable byte[] content) {
public void setContent(byte @Nullable [] content) {
this.content = content;
this.inputStream = null;
this.reader = null;
@@ -441,8 +421,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
* @see #setContent(byte[])
* @see #getContentAsString()
*/
@Nullable
public byte[] getContentAsByteArray() {
public byte @Nullable [] getContentAsByteArray() {
return this.content;
}
@@ -457,8 +436,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
* @see #setCharacterEncoding(String)
* @see #getContentAsByteArray()
*/
@Nullable
public String getContentAsString() throws IllegalStateException, UnsupportedEncodingException {
public @Nullable String getContentAsString() throws IllegalStateException, UnsupportedEncodingException {
Assert.state(this.characterEncoding != null,
"Cannot get content as a String for a null character encoding. " +
"Consider setting the characterEncoding in the request.");
@@ -501,8 +479,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getContentType() {
public @Nullable String getContentType() {
return this.contentType;
}
@@ -627,8 +604,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getParameter(String name) {
public @Nullable String getParameter(String name) {
Assert.notNull(name, "Parameter name must not be null");
String[] arr = this.parameters.get(name);
return (arr != null && arr.length > 0 ? arr[0] : null);
@@ -640,8 +616,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String[] getParameterValues(String name) {
public @Nullable String[] getParameterValues(String name) {
Assert.notNull(name, "Parameter name must not be null");
return this.parameters.get(name);
}
@@ -964,8 +939,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public AsyncContext getAsyncContext() {
public @Nullable AsyncContext getAsyncContext() {
return this.asyncContext;
}
@@ -1020,8 +994,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getAuthType() {
public @Nullable String getAuthType() {
return this.authType;
}
@@ -1042,8 +1015,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public Cookie[] getCookies() {
public @Nullable Cookie[] getCookies() {
return this.cookies;
}
@@ -1165,8 +1137,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getHeader(String name) {
public @Nullable String getHeader(String name) {
HeaderValueHolder header = this.headers.get(name);
return (header != null ? header.getStringValue() : null);
}
@@ -1206,8 +1177,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getMethod() {
public @Nullable String getMethod() {
return this.method;
}
@@ -1216,14 +1186,12 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getPathInfo() {
public @Nullable String getPathInfo() {
return this.pathInfo;
}
@Override
@Nullable
public String getPathTranslated() {
public @Nullable String getPathTranslated() {
return (this.pathInfo != null ? this.servletContext.getRealPath(this.pathInfo) : null);
}
@@ -1241,8 +1209,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getQueryString() {
public @Nullable String getQueryString() {
return this.queryString;
}
@@ -1251,8 +1218,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getRemoteUser() {
public @Nullable String getRemoteUser() {
return this.remoteUser;
}
@@ -1272,8 +1238,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public Principal getUserPrincipal() {
public @Nullable Principal getUserPrincipal() {
return this.userPrincipal;
}
@@ -1282,8 +1247,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getRequestedSessionId() {
public @Nullable String getRequestedSessionId() {
return this.requestedSessionId;
}
@@ -1300,8 +1264,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
* Return the original URI template used to prepare the request, if any.
* @since 6.2
*/
@Nullable
public String getUriTemplate() {
public @Nullable String getUriTemplate() {
return this.uriTemplate;
}
@@ -1310,8 +1273,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public String getRequestURI() {
public @Nullable String getRequestURI() {
return this.requestURI;
}
@@ -1350,8 +1312,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public HttpSession getSession(boolean create) {
public @Nullable HttpSession getSession(boolean create) {
checkActive();
// Reset session if invalidated.
if (this.session instanceof MockHttpSession mockSession && mockSession.isInvalid()) {
@@ -1365,8 +1326,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public HttpSession getSession() {
public @Nullable HttpSession getSession() {
return getSession(true);
}
@@ -1434,8 +1394,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
@Override
@Nullable
public Part getPart(String name) throws IOException, ServletException {
public @Nullable Part getPart(String name) throws IOException, ServletException {
return this.parts.getFirst(name);
}
@@ -1465,8 +1424,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
* This helps {@link org.springframework.web.util.ServletRequestPathUtils}
* to take into account the Servlet path when parsing the requestURI.
*/
@Nullable
private MappingMatch determineMappingMatch() {
private @Nullable MappingMatch determineMappingMatch() {
if (StringUtils.hasText(this.requestURI) && StringUtils.hasText(this.servletPath)) {
String path = UrlPathHelper.defaultInstance.getRequestUri(this);
String prefix = this.contextPath + this.servletPath;

View File

@@ -43,10 +43,10 @@ import java.util.TimeZone;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.StringUtils;
@@ -99,13 +99,11 @@ public class MockHttpServletResponse implements HttpServletResponse {
private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content);
@Nullable
private PrintWriter writer;
private @Nullable PrintWriter writer;
private long contentLength = 0;
@Nullable
private String contentType;
private @Nullable String contentType;
private int bufferSize = 4096;
@@ -124,16 +122,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
private int status = HttpServletResponse.SC_OK;
@Nullable
private String errorMessage;
private @Nullable String errorMessage;
//---------------------------------------------------------------------
// Properties for MockRequestDispatcher
//---------------------------------------------------------------------
@Nullable
private String forwardedUrl;
private @Nullable String forwardedUrl;
private final List<String> includedUrls = new ArrayList<>();
@@ -372,8 +368,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
}
@Override
@Nullable
public String getContentType() {
public @Nullable String getContentType() {
return this.contentType;
}
@@ -510,8 +505,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
return this.cookies.toArray(new Cookie[0]);
}
@Nullable
public Cookie getCookie(String name) {
public @Nullable Cookie getCookie(String name) {
Assert.notNull(name, "Cookie name must not be null");
for (Cookie cookie : this.cookies) {
if (name.equals(cookie.getName())) {
@@ -546,8 +540,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
* @see HttpServletResponse#getHeader(String)
*/
@Override
@Nullable
public String getHeader(String name) {
public @Nullable String getHeader(String name) {
HeaderValueHolder header = this.headers.get(name);
return (header != null ? header.getStringValue() : null);
}
@@ -577,8 +570,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
* @param name the name of the header
* @return the associated header value, or {@code null} if none
*/
@Nullable
public Object getHeaderValue(String name) {
public @Nullable Object getHeaderValue(String name) {
HeaderValueHolder header = this.headers.get(name);
return (header != null ? header.getValue() : null);
}
@@ -649,8 +641,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
setCommitted(true);
}
@Nullable
public String getRedirectedUrl() {
public @Nullable String getRedirectedUrl() {
return getHeader(HttpHeaders.LOCATION);
}
@@ -807,8 +798,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
/**
* Return the error message used when calling {@link HttpServletResponse#sendError(int, String)}.
*/
@Nullable
public String getErrorMessage() {
public @Nullable String getErrorMessage() {
return this.errorMessage;
}
@@ -821,8 +811,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
this.forwardedUrl = forwardedUrl;
}
@Nullable
public String getForwardedUrl() {
public @Nullable String getForwardedUrl() {
return this.forwardedUrl;
}
@@ -833,8 +822,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
}
}
@Nullable
public String getIncludedUrl() {
public @Nullable String getIncludedUrl() {
int count = this.includedUrls.size();
Assert.state(count <= 1,
() -> "More than 1 URL included - check getIncludedUrls instead: " + this.includedUrls);

View File

@@ -29,8 +29,8 @@ import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -22,8 +22,7 @@ import java.io.Writer;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.jsp.JspWriter;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Mock implementation of the {@link jakarta.servlet.jsp.JspWriter} class.
@@ -36,8 +35,7 @@ public class MockJspWriter extends JspWriter {
private final HttpServletResponse response;
@Nullable
private PrintWriter targetWriter;
private @Nullable PrintWriter targetWriter;
/**

View File

@@ -21,8 +21,9 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
@@ -45,8 +46,7 @@ public class MockMultipartFile implements MultipartFile {
private final String originalFilename;
@Nullable
private final String contentType;
private final @Nullable String contentType;
private final byte[] content;
@@ -56,7 +56,7 @@ public class MockMultipartFile implements MultipartFile {
* @param name the name of the file
* @param content the content of the file
*/
public MockMultipartFile(String name, @Nullable byte[] content) {
public MockMultipartFile(String name, byte @Nullable [] content) {
this(name, "", null, content);
}
@@ -78,7 +78,7 @@ public class MockMultipartFile implements MultipartFile {
* @param content the content of the file
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
String name, @Nullable String originalFilename, @Nullable String contentType, byte @Nullable [] content) {
Assert.hasLength(name, "Name must not be empty");
this.name = name;
@@ -109,14 +109,12 @@ public class MockMultipartFile implements MultipartFile {
}
@Override
@NonNull
public String getOriginalFilename() {
public @NonNull String getOriginalFilename() {
return this.originalFilename;
}
@Override
@Nullable
public String getContentType() {
public @Nullable String getContentType() {
return this.contentType;
}

View File

@@ -28,10 +28,10 @@ import java.util.Objects;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Part;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

View File

@@ -36,8 +36,8 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.jsp.JspWriter;
import jakarta.servlet.jsp.PageContext;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -63,8 +63,7 @@ public class MockPageContext extends PageContext {
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Nullable
private JspWriter out;
private @Nullable JspWriter out;
/**
@@ -163,15 +162,13 @@ public class MockPageContext extends PageContext {
}
@Override
@Nullable
public Object getAttribute(String name) {
public @Nullable Object getAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
return this.attributes.get(name);
}
@Override
@Nullable
public Object getAttribute(String name, int scope) {
public @Nullable Object getAttribute(String name, int scope) {
Assert.notNull(name, "Attribute name must not be null");
return switch (scope) {
case PAGE_SCOPE -> getAttribute(name);
@@ -186,8 +183,7 @@ public class MockPageContext extends PageContext {
}
@Override
@Nullable
public Object findAttribute(String name) {
public @Nullable Object findAttribute(String name) {
Object value = getAttribute(name);
if (value == null) {
value = getAttribute(name, REQUEST_SCOPE);
@@ -268,8 +264,7 @@ public class MockPageContext extends PageContext {
}
@Override
@Nullable
public ELContext getELContext() {
public @Nullable ELContext getELContext() {
return null;
}
@@ -294,8 +289,7 @@ public class MockPageContext extends PageContext {
}
@Override
@Nullable
public Exception getException() {
public @Nullable Exception getException() {
return null;
}

View File

@@ -23,10 +23,10 @@ import java.util.Collection;
import java.util.Collections;
import jakarta.servlet.http.Part;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -42,8 +42,7 @@ public class MockPart implements Part {
private final String name;
@Nullable
private final String filename;
private final @Nullable String filename;
private final byte[] content;
@@ -54,7 +53,7 @@ public class MockPart implements Part {
* Constructor for a part with a name and content only.
* @see #getHeaders()
*/
public MockPart(String name, @Nullable byte[] content) {
public MockPart(String name, byte @Nullable [] content) {
this(name, null, content);
}
@@ -62,7 +61,7 @@ public class MockPart implements Part {
* Constructor for a part with a name, filename, and content.
* @see #getHeaders()
*/
public MockPart(String name, @Nullable String filename, @Nullable byte[] content) {
public MockPart(String name, @Nullable String filename, byte @Nullable [] content) {
this(name, filename, content, null);
}
@@ -71,7 +70,7 @@ public class MockPart implements Part {
* @since 6.1.2
* @see #getHeaders()
*/
public MockPart(String name, @Nullable String filename, @Nullable byte[] content, @Nullable MediaType contentType) {
public MockPart(String name, @Nullable String filename, byte @Nullable [] content, @Nullable MediaType contentType) {
Assert.hasLength(name, "'name' must not be empty");
this.name = name;
this.filename = filename;
@@ -87,14 +86,12 @@ public class MockPart implements Part {
}
@Override
@Nullable
public String getSubmittedFileName() {
public @Nullable String getSubmittedFileName() {
return this.filename;
}
@Override
@Nullable
public String getContentType() {
public @Nullable String getContentType() {
MediaType contentType = this.headers.getContentType();
return (contentType != null ? contentType.toString() : null);
}
@@ -120,8 +117,7 @@ public class MockPart implements Part {
}
@Override
@Nullable
public String getHeader(String name) {
public @Nullable String getHeader(String name) {
return this.headers.getFirst(name);
}

View File

@@ -23,8 +23,8 @@ import java.util.Map;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -43,13 +43,13 @@ import jakarta.servlet.SessionTrackingMode;
import jakarta.servlet.descriptor.JspConfigDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -132,18 +132,15 @@ public class MockServletContext implements ServletContext {
private final Set<String> declaredRoles = new LinkedHashSet<>();
@Nullable
private Set<SessionTrackingMode> sessionTrackingModes;
private @Nullable Set<SessionTrackingMode> sessionTrackingModes;
private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig();
private int sessionTimeout;
@Nullable
private String requestCharacterEncoding;
private @Nullable String requestCharacterEncoding;
@Nullable
private String responseCharacterEncoding;
private @Nullable String responseCharacterEncoding;
private final Map<String, FilterRegistration> filterRegistrations = new LinkedHashMap<>();
@@ -226,8 +223,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public ServletContext getContext(String contextPath) {
public @Nullable ServletContext getContext(String contextPath) {
if (this.contextPath.equals(contextPath)) {
return this;
}
@@ -271,8 +267,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public String getMimeType(String filePath) {
public @Nullable String getMimeType(String filePath) {
String extension = StringUtils.getFilenameExtension(filePath);
if (this.mimeTypes.containsKey(extension)) {
return this.mimeTypes.get(extension).toString();
@@ -295,8 +290,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public Set<String> getResourcePaths(String path) {
public @Nullable Set<String> getResourcePaths(String path) {
String actualPath = (path.endsWith("/") ? path : path + "/");
String resourceLocation = getResourceLocation(actualPath);
Resource resource = null;
@@ -327,8 +321,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public URL getResource(String path) throws MalformedURLException {
public @Nullable URL getResource(String path) throws MalformedURLException {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
@@ -351,8 +344,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public InputStream getResourceAsStream(String path) {
public @Nullable InputStream getResourceAsStream(String path) {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
@@ -379,8 +371,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public RequestDispatcher getNamedDispatcher(String path) {
public @Nullable RequestDispatcher getNamedDispatcher(String path) {
return this.namedRequestDispatchers.get(path);
}
@@ -446,8 +437,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public String getRealPath(String path) {
public @Nullable String getRealPath(String path) {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
@@ -469,8 +459,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public String getInitParameter(String name) {
public @Nullable String getInitParameter(String name) {
Assert.notNull(name, "Parameter name must not be null");
return this.initParameters.get(name);
}
@@ -496,8 +485,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public Object getAttribute(String name) {
public @Nullable Object getAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
return this.attributes.get(name);
}
@@ -534,8 +522,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public ClassLoader getClassLoader() {
public @Nullable ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
@@ -590,8 +577,7 @@ public class MockServletContext implements ServletContext {
}
@Override // on Servlet 4.0
@Nullable
public String getRequestCharacterEncoding() {
public @Nullable String getRequestCharacterEncoding() {
return this.requestCharacterEncoding;
}
@@ -601,8 +587,7 @@ public class MockServletContext implements ServletContext {
}
@Override // on Servlet 4.0
@Nullable
public String getResponseCharacterEncoding() {
public @Nullable String getResponseCharacterEncoding() {
return this.responseCharacterEncoding;
}
@@ -615,8 +600,7 @@ public class MockServletContext implements ServletContext {
}
@Override
@Nullable
public FilterRegistration getFilterRegistration(String filterName) {
public @Nullable FilterRegistration getFilterRegistration(String filterName) {
return this.filterRegistrations.get(filterName);
}
@@ -665,8 +649,7 @@ public class MockServletContext implements ServletContext {
* @see jakarta.servlet.ServletContext#getServletRegistration(java.lang.String)
*/
@Override
@Nullable
public ServletRegistration getServletRegistration(String servletName) {
public @Nullable ServletRegistration getServletRegistration(String servletName) {
return null;
}

View File

@@ -21,8 +21,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import jakarta.servlet.SessionCookieConfig;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Mock implementation of the {@link jakarta.servlet.SessionCookieConfig} interface.
@@ -33,17 +32,13 @@ import org.springframework.lang.Nullable;
*/
public class MockSessionCookieConfig implements SessionCookieConfig {
@Nullable
private String name;
private @Nullable String name;
@Nullable
private String domain;
private @Nullable String domain;
@Nullable
private String path;
private @Nullable String path;
@Nullable
private String comment;
private @Nullable String comment;
private boolean httpOnly;
@@ -60,8 +55,7 @@ public class MockSessionCookieConfig implements SessionCookieConfig {
}
@Override
@Nullable
public String getName() {
public @Nullable String getName() {
return this.name;
}
@@ -71,8 +65,7 @@ public class MockSessionCookieConfig implements SessionCookieConfig {
}
@Override
@Nullable
public String getDomain() {
public @Nullable String getDomain() {
return this.domain;
}
@@ -82,8 +75,7 @@ public class MockSessionCookieConfig implements SessionCookieConfig {
}
@Override
@Nullable
public String getPath() {
public @Nullable String getPath() {
return this.path;
}
@@ -95,8 +87,7 @@ public class MockSessionCookieConfig implements SessionCookieConfig {
@SuppressWarnings("removal")
@Override
@Nullable
public String getComment() {
public @Nullable String getComment() {
return this.comment;
}

View File

@@ -24,8 +24,8 @@ import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -42,14 +42,11 @@ import org.springframework.util.Assert;
*/
public class PassThroughFilterChain implements FilterChain {
@Nullable
private Filter filter;
private @Nullable Filter filter;
@Nullable
private FilterChain nextFilterChain;
private @Nullable FilterChain nextFilterChain;
@Nullable
private Servlet servlet;
private @Nullable Servlet servlet;
/**

View File

@@ -17,8 +17,7 @@
package org.springframework.web.testfixture.xml;
import jakarta.xml.bind.annotation.XmlRootElement;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* @author Sebastien Deleuze