Skip to content

Commit a442c18

Browse files
committed
Refine null-safety in the spring-test module
Closes gh-34161
1 parent 7417bd0 commit a442c18

19 files changed

+47
-29
lines changed

spring-test/src/main/java/org/springframework/test/context/jdbc/SqlScriptsTestExecutionListener.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ private String[] getScripts(Sql sql, Class<?> testClass, @Nullable Method testMe
410410
* Detect a default SQL script by implementing the algorithm defined in
411411
* {@link Sql#scripts}.
412412
*/
413-
@SuppressWarnings("NullAway")
413+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
414414
private String detectDefaultScript(Class<?> testClass, @Nullable Method testMethod, boolean classLevel) {
415415
Assert.state(classLevel || testMethod != null, "Method-level @Sql requires a testMethod");
416416

spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ private static Store getStore(ExtensionContext context) {
373373
* the supplied {@link TestContextManager}.
374374
* @since 6.1
375375
*/
376-
@SuppressWarnings("NullAway")
376+
@SuppressWarnings("NullAway") // org.junit.jupiter.api.extension.ExecutableInvoker is not null marked
377377
private static void registerMethodInvoker(TestContextManager testContextManager, ExtensionContext context) {
378378
testContextManager.getTestContext().setMethodInvoker(context.getExecutableInvoker()::invoke);
379379
}

spring-test/src/main/java/org/springframework/test/context/support/AbstractDirtiesContextTestExecutionListener.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ protected void dirtyContext(TestContext testContext, @Nullable HierarchyMode hie
8484
* @since 4.2
8585
* @see #dirtyContext
8686
*/
87-
@SuppressWarnings("NullAway")
87+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
8888
protected void beforeOrAfterTestMethod(TestContext testContext, MethodMode requiredMethodMode,
8989
ClassMode requiredClassMode) throws Exception {
9090

@@ -136,7 +136,7 @@ else if (logger.isDebugEnabled()) {
136136
* @since 4.2
137137
* @see #dirtyContext
138138
*/
139-
@SuppressWarnings("NullAway")
139+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
140140
protected void beforeOrAfterTestClass(TestContext testContext, ClassMode requiredClassMode) throws Exception {
141141
Assert.notNull(testContext, "TestContext must not be null");
142142
Assert.notNull(requiredClassMode, "requiredClassMode must not be null");

spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ static Map<String, List<ContextConfigurationAttributes>> buildContextHierarchyMa
232232
* @throws IllegalArgumentException if the supplied class is {@code null} or if
233233
* {@code @ContextConfiguration} is not <em>present</em> on the supplied class
234234
*/
235-
@SuppressWarnings("NullAway")
235+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
236236
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> testClass) {
237237
Assert.notNull(testClass, "Class must not be null");
238238

spring-test/src/main/java/org/springframework/test/context/support/TestPropertySourceUtils.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ else if (!duplicationDetected(currentAttributes, previousAttributes)) {
134134
return mergedAttributes;
135135
}
136136

137-
@SuppressWarnings("NullAway")
137+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
138138
private static boolean duplicationDetected(TestPropertySourceAttributes currentAttributes,
139139
@Nullable TestPropertySourceAttributes previousAttributes) {
140140

spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public final int getOrder() {
194194
* @see #getTransactionManager(TestContext, String)
195195
*/
196196
@Override
197-
@SuppressWarnings("NullAway")
197+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
198198
public void beforeTestMethod(final TestContext testContext) throws Exception {
199199
Method testMethod = testContext.getTestMethod();
200200
Class<?> testClass = testContext.getTestClass();

spring-test/src/main/java/org/springframework/test/http/MediaTypeAssert.java

-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ public MediaTypeAssert isCompatibleWith(String mediaType) {
103103
}
104104

105105

106-
@SuppressWarnings("NullAway")
107106
private MediaType parseMediaType(String value) {
108107
try {
109108
return MediaType.parseMediaType(value);

spring-test/src/main/java/org/springframework/test/json/AbstractJsonContentAssert.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ public SELF withCharset(@Nullable Charset charset) {
489489
return (this.actual != null ? this.actual.getJson() : null);
490490
}
491491

492-
@SuppressWarnings("NullAway")
492+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
493493
private String toNonNullJsonString() {
494494
String jsonString = toJsonString();
495495
Assertions.assertThat(jsonString).as("JSON content").isNotNull();

spring-test/src/main/java/org/springframework/test/util/ReflectionTestUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public static void setField(
173173
* @see ReflectionUtils#setField(Field, Object, Object)
174174
* @see AopTestUtils#getUltimateTargetObject(Object)
175175
*/
176-
@SuppressWarnings("NullAway")
176+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
177177
public static void setField(@Nullable Object targetObject, @Nullable Class<?> targetClass,
178178
@Nullable String name, @Nullable Object value, @Nullable Class<?> type) {
179179

@@ -258,7 +258,7 @@ public static void setField(@Nullable Object targetObject, @Nullable Class<?> ta
258258
* @see ReflectionUtils#getField(Field, Object)
259259
* @see AopTestUtils#getUltimateTargetObject(Object)
260260
*/
261-
@SuppressWarnings("NullAway")
261+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
262262
public static @Nullable Object getField(@Nullable Object targetObject, @Nullable Class<?> targetClass, String name) {
263263
Assert.isTrue(targetObject != null || targetClass != null,
264264
"Either targetObject or targetClass for the field must be specified");

spring-test/src/main/java/org/springframework/test/web/ModelAndViewAssert.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public static void assertModelAttributeValue(ModelAndView mav, String modelName,
109109
* @param mav the ModelAndView to test against (never {@code null})
110110
* @param expectedModel the expected model
111111
*/
112-
@SuppressWarnings("NullAway")
112+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
113113
public static void assertModelAttributeValues(ModelAndView mav, Map<String, Object> expectedModel) {
114114
Map<String, Object> model = mav.getModel();
115115

spring-test/src/main/java/org/springframework/test/web/UriAssert.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,32 @@ public UriAssert matchesAntPattern(String uriPattern) {
8080
return this;
8181
}
8282

83-
@SuppressWarnings("NullAway")
83+
8484
private String buildUri(String uriTemplate, Object... uriVars) {
8585
try {
8686
return UriComponentsBuilder.fromUriString(uriTemplate)
8787
.buildAndExpand(uriVars).encode().toUriString();
8888
}
8989
catch (Exception ex) {
90+
String message = ex.getMessage();
9091
throw Failures.instance().failure(this.info,
91-
new ShouldBeValidUriTemplate(uriTemplate, ex.getMessage()));
92+
message == null ?
93+
new ShouldBeValidUriTemplate(uriTemplate) :
94+
new ShouldBeValidUriTemplateWithMessage(uriTemplate, message));
9295
}
9396
}
9497

9598

9699
private static final class ShouldBeValidUriTemplate extends BasicErrorMessageFactory {
97100

98-
private ShouldBeValidUriTemplate(String uriTemplate, String errorMessage) {
101+
private ShouldBeValidUriTemplate(String uriTemplate) {
102+
super("%nExpecting:%n %s%nTo be a valid URI template%n", uriTemplate);
103+
}
104+
}
105+
106+
private static final class ShouldBeValidUriTemplateWithMessage extends BasicErrorMessageFactory {
107+
108+
private ShouldBeValidUriTemplateWithMessage(String uriTemplate, String errorMessage) {
99109
super("%nExpecting:%n %s%nTo be a valid URI template but got:%n %s%n", uriTemplate, errorMessage);
100110
}
101111
}

spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public static RequestMatcher queryParamList(String name, Matcher<? super List<St
159159
* @see #queryParam(String, String...)
160160
*/
161161
@SafeVarargs
162-
@SuppressWarnings("NullAway")
162+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
163163
public static RequestMatcher queryParam(String name, Matcher<? super String>... matchers) {
164164
return request -> {
165165
MultiValueMap<String, String> params = getQueryParams(request);
@@ -187,7 +187,7 @@ public static RequestMatcher queryParam(String name, Matcher<? super String>...
187187
* @see #queryParamList(String, Matcher)
188188
* @see #queryParam(String, Matcher...)
189189
*/
190-
@SuppressWarnings("NullAway")
190+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
191191
public static RequestMatcher queryParam(String name, String... expectedValues) {
192192
return request -> {
193193
MultiValueMap<String, String> params = getQueryParams(request);

spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class WiretapConnector implements ClientHttpConnector {
6262

6363

6464
@Override
65-
@SuppressWarnings("NullAway")
65+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
6666
public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
6767
Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {
6868

@@ -180,7 +180,7 @@ public Publisher<? extends Publisher<? extends DataBuffer>> getNestedPublisherTo
180180
return this.publisherNested;
181181
}
182182

183-
@SuppressWarnings("NullAway")
183+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
184184
public Mono<byte[]> getContent() {
185185
return Mono.defer(() -> {
186186
if (this.content.scan(Scannable.Attr.TERMINATED) == Boolean.TRUE) {

spring-test/src/main/java/org/springframework/test/web/servlet/DefaultMvcResult.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,12 @@ public void setAsyncResult(@Nullable Object asyncResult) {
124124
}
125125

126126
@Override
127-
public Object getAsyncResult() {
127+
public @Nullable Object getAsyncResult() {
128128
return getAsyncResult(-1);
129129
}
130130

131131
@Override
132-
@SuppressWarnings("NullAway")
133-
public Object getAsyncResult(long timeToWait) {
132+
public @Nullable Object getAsyncResult(long timeToWait) {
134133
if (this.mockRequest.getAsyncContext() != null && timeToWait == -1) {
135134
long requestTimeout = this.mockRequest.getAsyncContext().getTimeout();
136135
timeToWait = requestTimeout == -1 ? Long.MAX_VALUE : requestTimeout;

spring-test/src/main/java/org/springframework/test/web/servlet/MvcResult.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public interface MvcResult {
8585
* {@link #getAsyncResult(long)} to specify the amount of time to wait.
8686
* @throws IllegalStateException if the async result was not set
8787
*/
88-
Object getAsyncResult();
88+
@Nullable Object getAsyncResult();
8989

9090
/**
9191
* Get the result of async execution and wait if necessary.
@@ -96,6 +96,6 @@ public interface MvcResult {
9696
* MockAsyncContext#setTimeout} for more details.
9797
* @throws IllegalStateException if the async result was not set
9898
*/
99-
Object getAsyncResult(long timeToWait);
99+
@Nullable Object getAsyncResult(long timeToWait);
100100

101101
}

spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MvcTestResultAssert.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public MvcTestResultAssert hasViewName(String viewName) {
212212
return this.actual.getMvcResult().getResolvedException();
213213
}
214214

215-
@SuppressWarnings("NullAway")
215+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
216216
private ModelAndView getModelAndView() {
217217
ModelAndView modelAndView = getMvcResult().getModelAndView();
218218
Assertions.assertThat(modelAndView).as("ModelAndView").isNotNull();

spring-test/src/main/java/org/springframework/test/web/servlet/client/MockMvcHttpConnector.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ public FlashMap getFlashMap() {
292292
}
293293

294294
@Override
295-
public Object getAsyncResult() {
295+
public @Nullable Object getAsyncResult() {
296296
return this.mvcResult.getAsyncResult();
297297
}
298298

299299
@Override
300-
public Object getAsyncResult(long timeToWait) {
300+
public @Nullable Object getAsyncResult(long timeToWait) {
301301
return this.mvcResult.getAsyncResult(timeToWait);
302302
}
303303

spring-test/src/test/java/org/springframework/test/web/servlet/StubMvcResult.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.test.web.servlet;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.mock.web.MockHttpServletRequest;
2022
import org.springframework.mock.web.MockHttpServletResponse;
2123
import org.springframework.web.servlet.FlashMap;
@@ -127,12 +129,12 @@ public void setResponse(MockHttpServletResponse response) {
127129
}
128130

129131
@Override
130-
public Object getAsyncResult() {
132+
public @Nullable Object getAsyncResult() {
131133
return null;
132134
}
133135

134136
@Override
135-
public Object getAsyncResult(long timeToWait) {
137+
public @Nullable Object getAsyncResult(long timeToWait) {
136138
return null;
137139
}
138140

spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java

+8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ public InvalidMediaTypeException(String mediaType, @Nullable String message) {
5151
this.mediaType = ex.getMimeType();
5252
}
5353

54+
/**
55+
* Returns the detail message string of this exception instance (never {@code null}).
56+
*/
57+
@Override
58+
@SuppressWarnings("NullAway") // InvalidMediaTypeException message is never null
59+
public String getMessage() {
60+
return super.getMessage();
61+
}
5462

5563
/**
5664
* Return the offending media type.

0 commit comments

Comments
 (0)