Skip to content

Commit 380c9e3

Browse files
committed
Specify generic type nullness in spring-web
See spring-projectsgh-34140
1 parent e2216dd commit 380c9e3

File tree

12 files changed

+54
-44
lines changed

12 files changed

+54
-44
lines changed

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -738,14 +738,14 @@ public static class UriTemplateRequestEntity<T> extends RequestEntity<T> {
738738

739739
private final String uriTemplate;
740740

741-
private final Object @Nullable [] uriVarsArray;
741+
private final @Nullable Object @Nullable [] uriVarsArray;
742742

743-
private final @Nullable Map<String, ?> uriVarsMap;
743+
private final @Nullable Map<String, ? extends @Nullable Object> uriVarsMap;
744744

745745
UriTemplateRequestEntity(
746746
@Nullable T body, @Nullable HttpHeaders headers,
747747
@Nullable HttpMethod method, @Nullable Type type, String uriTemplate,
748-
Object @Nullable [] uriVarsArray, @Nullable Map<String, ?> uriVarsMap) {
748+
@Nullable Object @Nullable [] uriVarsArray, @Nullable Map<String, ?> uriVarsMap) {
749749

750750
super(body, headers, method, null, type);
751751
this.uriTemplate = uriTemplate;
@@ -757,11 +757,11 @@ public String getUriTemplate() {
757757
return this.uriTemplate;
758758
}
759759

760-
public Object @Nullable [] getVars() {
760+
public @Nullable Object @Nullable [] getVars() {
761761
return this.uriVarsArray;
762762
}
763763

764-
public @Nullable Map<String, ?> getVarsMap() {
764+
public @Nullable Map<String, ? extends @Nullable Object> getVarsMap() {
765765
return this.uriVarsMap;
766766
}
767767

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -260,7 +260,7 @@ public Jackson2ObjectMapperBuilder annotationIntrospector(AnnotationIntrospector
260260
* @since 5.2.4
261261
*/
262262
public Jackson2ObjectMapperBuilder annotationIntrospector(
263-
Function<AnnotationIntrospector, AnnotationIntrospector> pairingFunction) {
263+
Function<@Nullable AnnotationIntrospector, @Nullable AnnotationIntrospector> pairingFunction) {
264264

265265
this.annotationIntrospector = pairingFunction.apply(this.annotationIntrospector);
266266
return this;

spring-web/src/main/java/org/springframework/web/client/RestClientResponseException.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -56,7 +56,7 @@ public class RestClientResponseException extends RestClientException {
5656

5757
private final @Nullable String responseCharset;
5858

59-
private transient @Nullable Function<ResolvableType, ?> bodyConvertFunction;
59+
private transient @Nullable Function<ResolvableType, ? extends @Nullable Object> bodyConvertFunction;
6060

6161

6262
/**
@@ -200,7 +200,7 @@ public String getResponseBodyAsString(Charset fallbackCharset) {
200200
* @param bodyConvertFunction the function to use
201201
* @since 6.0
202202
*/
203-
public void setBodyConvertFunction(Function<ResolvableType, ?> bodyConvertFunction) {
203+
public void setBodyConvertFunction(Function<ResolvableType, ? extends @Nullable Object> bodyConvertFunction) {
204204
this.bodyConvertFunction = bodyConvertFunction;
205205
}
206206

spring-web/src/main/java/org/springframework/web/client/StatusHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -99,7 +99,8 @@ else if (statusCode.is5xxServerError()) {
9999
});
100100
}
101101

102-
private static Function<ResolvableType, ?> initBodyConvertFunction(ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
102+
@SuppressWarnings("NullAway")
103+
private static Function<ResolvableType, ? extends @Nullable Object> initBodyConvertFunction(ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
103104
Assert.state(!CollectionUtils.isEmpty(messageConverters), "Expected message converters");
104105
return resolvableType -> {
105106
try {

spring-web/src/main/java/org/springframework/web/filter/FormContentFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -159,7 +159,7 @@ public Enumeration<String> getParameterNames() {
159159
}
160160

161161
@Override
162-
public @Nullable String[] getParameterValues(String name) {
162+
public String[] getParameterValues(String name) {
163163
String[] parameterValues = super.getParameterValues(name);
164164
List<String> formParam = this.formParams.get(name);
165165
if (formParam == null) {

spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -357,7 +357,7 @@ public String toString() {
357357
* beans, and others). {@code @Controller}'s that require proxying should prefer
358358
* class-based proxy mechanisms.
359359
*/
360-
protected void assertTargetBean(Method method, Object targetBean, Object[] args) {
360+
protected void assertTargetBean(Method method, Object targetBean, @Nullable Object[] args) {
361361
Class<?> methodDeclaringClass = method.getDeclaringClass();
362362
Class<?> targetBeanClass = targetBean.getClass();
363363
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
@@ -369,11 +369,14 @@ protected void assertTargetBean(Method method, Object targetBean, Object[] args)
369369
}
370370
}
371371

372-
protected String formatInvokeError(String text, Object[] args) {
372+
protected String formatInvokeError(String text, @Nullable Object[] args) {
373373
String formattedArgs = IntStream.range(0, args.length)
374-
.mapToObj(i -> (args[i] != null ?
375-
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
376-
"[" + i + "] [null]"))
374+
.mapToObj(i -> {
375+
Object arg = args[i];
376+
return (arg != null ?
377+
"[" + i + "] [type=" +arg.getClass().getName() + "] [value=" + arg + "]" :
378+
"[" + i + "] [null]");
379+
})
377380
.collect(Collectors.joining(",\n", " ", " "));
378381
return text + "\n" +
379382
"Controller [" + getBeanType().getName() + "]\n" +

spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import java.util.HashSet;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.Objects;
2728
import java.util.Set;
2829

2930
import org.jspecify.annotations.Nullable;
@@ -226,7 +227,7 @@ public boolean hasExceptionMappings() {
226227
* Return the {@link Method} mapped to the given exception type, or
227228
* {@link #NO_MATCHING_EXCEPTION_HANDLER} if none.
228229
*/
229-
private @Nullable ExceptionHandlerMappingInfo getMappedMethod(Class<? extends Throwable> exceptionType, MediaType mediaType) {
230+
private ExceptionHandlerMappingInfo getMappedMethod(Class<? extends Throwable> exceptionType, MediaType mediaType) {
230231
List<ExceptionMapping> matches = new ArrayList<>();
231232
for (ExceptionMapping mappingInfo : this.mappedMethods.keySet()) {
232233
if (mappingInfo.exceptionType().isAssignableFrom(exceptionType) && mappingInfo.mediaType().isCompatibleWith(mediaType)) {
@@ -237,7 +238,7 @@ public boolean hasExceptionMappings() {
237238
if (matches.size() > 1) {
238239
matches.sort(new ExceptionMapingComparator(exceptionType, mediaType));
239240
}
240-
return this.mappedMethods.get(matches.get(0));
241+
return Objects.requireNonNull(this.mappedMethods.get(matches.get(0)));
241242
}
242243
else {
243244
return NO_MATCHING_EXCEPTION_HANDLER;

spring-web/src/main/java/org/springframework/web/method/annotation/HandlerMethodValidator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ public Class<?>[] determineValidationGroups(Object target, Method method) {
7878
@Override
7979
public void applyArgumentValidation(
8080
Object target, Method method, MethodParameter @Nullable [] parameters,
81-
Object[] arguments, Class<?>[] groups) {
81+
@Nullable Object[] arguments, Class<?>[] groups) {
8282

8383
MethodValidationResult result = validateArguments(target, method, parameters, arguments, groups);
8484
if (!result.hasErrors()) {
@@ -110,7 +110,7 @@ public void applyArgumentValidation(
110110
@Override
111111
public MethodValidationResult validateArguments(
112112
Object target, Method method, MethodParameter @Nullable [] parameters,
113-
Object[] arguments, Class<?>[] groups) {
113+
@Nullable Object[] arguments, Class<?>[] groups) {
114114

115115
return this.validationAdapter.validateArguments(target, method, parameters, arguments, groups);
116116
}

spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -172,9 +172,9 @@ public void setMethodValidator(@Nullable MethodValidator methodValidator) {
172172
* @see #doInvoke
173173
*/
174174
public @Nullable Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
175-
Object... providedArgs) throws Exception {
175+
@Nullable Object... providedArgs) throws Exception {
176176

177-
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
177+
@Nullable Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
178178
if (logger.isTraceEnabled()) {
179179
logger.trace("Arguments: " + Arrays.toString(args));
180180
}
@@ -200,15 +200,15 @@ public void setMethodValidator(@Nullable MethodValidator methodValidator) {
200200
* <p>The resulting array will be passed into {@link #doInvoke}.
201201
* @since 5.1.2
202202
*/
203-
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
204-
Object... providedArgs) throws Exception {
203+
protected @Nullable Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
204+
@Nullable Object... providedArgs) throws Exception {
205205

206206
MethodParameter[] parameters = getMethodParameters();
207207
if (ObjectUtils.isEmpty(parameters)) {
208208
return EMPTY_ARGS;
209209
}
210210

211-
Object[] args = new Object[parameters.length];
211+
@Nullable Object[] args = new Object[parameters.length];
212212
for (int i = 0; i < parameters.length; i++) {
213213
MethodParameter parameter = parameters[i];
214214
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
@@ -239,7 +239,7 @@ protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable M
239239
/**
240240
* Invoke the handler method with the given argument values.
241241
*/
242-
protected @Nullable Object doInvoke(Object... args) throws Exception {
242+
protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception {
243243
Method method = getBridgedMethod();
244244
try {
245245
if (KotlinDetector.isKotlinReflectPresent()) {
@@ -285,7 +285,7 @@ else if (targetException instanceof Exception exception) {
285285
* instead.
286286
* @since 6.0
287287
*/
288-
protected Object invokeSuspendingFunction(Method method, Object target, Object[] args) {
288+
protected Object invokeSuspendingFunction(Method method, Object target, @Nullable Object[] args) {
289289
Object result = CoroutinesUtils.invokeSuspendingFunction(method, target, args);
290290
return (result instanceof Mono<?> mono ? mono.handle(KotlinDelegate::handleResult) : result);
291291
}
@@ -297,7 +297,9 @@ protected Object invokeSuspendingFunction(Method method, Object target, Object[]
297297
private static class KotlinDelegate {
298298

299299
@SuppressWarnings("DataFlowIssue")
300-
public static @Nullable Object invokeFunction(Method method, Object target, Object[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
300+
public static @Nullable Object invokeFunction(Method method, Object target, @Nullable Object[] args) throws
301+
InvocationTargetException, IllegalAccessException, NoSuchMethodException {
302+
301303
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
302304
// For property accessors
303305
if (function == null) {

spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -127,13 +127,13 @@ public Method getMethod() {
127127
}
128128

129129

130-
public @Nullable Object invoke(Object[] arguments) {
130+
public @Nullable Object invoke(@Nullable Object[] arguments) {
131131
HttpRequestValues.Builder requestValues = this.requestValuesInitializer.initializeRequestValuesBuilder();
132132
applyArguments(requestValues, arguments);
133133
return this.responseFunction.execute(requestValues.build());
134134
}
135135

136-
private void applyArguments(HttpRequestValues.Builder requestValues, Object[] arguments) {
136+
private void applyArguments(HttpRequestValues.Builder requestValues, @Nullable Object[] arguments) {
137137
Assert.isTrue(arguments.length == this.parameters.length, "Method argument mismatch");
138138
for (int i = 0; i < arguments.length; i++) {
139139
Object value = arguments[i];
@@ -383,10 +383,10 @@ private interface ResponseFunction {
383383
}
384384

385385
private record ExchangeResponseFunction(
386-
Function<HttpRequestValues, Object> responseFunction) implements ResponseFunction {
386+
Function<HttpRequestValues, @Nullable Object> responseFunction) implements ResponseFunction {
387387

388388
@Override
389-
public Object execute(HttpRequestValues requestValues) {
389+
public @Nullable Object execute(HttpRequestValues requestValues) {
390390
return this.responseFunction.apply(requestValues);
391391
}
392392

@@ -403,7 +403,7 @@ public static ResponseFunction create(HttpExchangeAdapter client, Method method)
403403
MethodParameter param = new MethodParameter(method, -1).nestedIfOptional();
404404
Class<?> paramType = param.getNestedParameterType();
405405

406-
Function<HttpRequestValues, Object> responseFunction;
406+
Function<HttpRequestValues, @Nullable Object> responseFunction;
407407
if (ClassUtils.isVoidType(paramType)) {
408408
responseFunction = requestValues -> {
409409
client.exchange(requestValues);

spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -233,7 +233,7 @@ private HttpServiceMethodInterceptor(List<HttpServiceMethod> methods) {
233233
Method method = invocation.getMethod();
234234
HttpServiceMethod httpServiceMethod = this.httpServiceMethods.get(method);
235235
if (httpServiceMethod != null) {
236-
Object[] arguments = KotlinDetector.isSuspendingFunction(method) ?
236+
@Nullable Object[] arguments = KotlinDetector.isSuspendingFunction(method) ?
237237
resolveCoroutinesArguments(invocation.getArguments()) : invocation.getArguments();
238238
return httpServiceMethod.invoke(arguments);
239239
}
@@ -246,7 +246,7 @@ private HttpServiceMethodInterceptor(List<HttpServiceMethod> methods) {
246246
throw new IllegalStateException("Unexpected method invocation: " + method);
247247
}
248248

249-
private static Object[] resolveCoroutinesArguments(Object[] args) {
249+
private static Object[] resolveCoroutinesArguments(@Nullable Object[] args) {
250250
Object[] functionArgs = new Object[args.length - 1];
251251
System.arraycopy(args, 0, functionArgs, 0, args.length - 1);
252252
return functionArgs;

spring-web/src/main/java/org/springframework/web/util/DefaultUriBuilderFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public EncodingMode getEncodingMode() {
140140
* with a Map of variables.
141141
* @param defaultUriVariables default URI variable values
142142
*/
143+
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
143144
public void setDefaultUriVariables(@Nullable Map<String, ? extends @Nullable Object> defaultUriVariables) {
144145
if (defaultUriVariables != null) {
145146
if (this.defaultUriVariables == null) {
@@ -431,6 +432,7 @@ public DefaultUriBuilder fragment(@Nullable String fragment) {
431432
}
432433

433434
@Override
435+
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
434436
public URI build(Map<String, ?> uriVars) {
435437
if (!CollectionUtils.isEmpty(defaultUriVariables)) {
436438
Map<String, Object> map = new HashMap<>(defaultUriVariables.size() + uriVars.size());
@@ -446,6 +448,7 @@ public URI build(Map<String, ?> uriVars) {
446448
}
447449

448450
@Override
451+
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
449452
public URI build(@Nullable Object... uriVars) {
450453
if (ObjectUtils.isEmpty(uriVars) && !CollectionUtils.isEmpty(defaultUriVariables)) {
451454
return build(Collections.emptyMap());

0 commit comments

Comments
 (0)