Specify generic type nullness in spring-web

See gh-34140
This commit is contained in:
Sébastien Deleuze
2025-01-13 20:54:25 +01:00
parent e2216ddc32
commit 380c9e318c
12 changed files with 54 additions and 44 deletions

View File

@@ -738,14 +738,14 @@ public class RequestEntity<T> extends HttpEntity<T> {
private final String uriTemplate;
private final Object @Nullable [] uriVarsArray;
private final @Nullable Object @Nullable [] uriVarsArray;
private final @Nullable Map<String, ?> uriVarsMap;
private final @Nullable Map<String, ? extends @Nullable Object> uriVarsMap;
UriTemplateRequestEntity(
@Nullable T body, @Nullable HttpHeaders headers,
@Nullable HttpMethod method, @Nullable Type type, String uriTemplate,
Object @Nullable [] uriVarsArray, @Nullable Map<String, ?> uriVarsMap) {
@Nullable Object @Nullable [] uriVarsArray, @Nullable Map<String, ?> uriVarsMap) {
super(body, headers, method, null, type);
this.uriTemplate = uriTemplate;
@@ -757,11 +757,11 @@ public class RequestEntity<T> extends HttpEntity<T> {
return this.uriTemplate;
}
public Object @Nullable [] getVars() {
public @Nullable Object @Nullable [] getVars() {
return this.uriVarsArray;
}
public @Nullable Map<String, ?> getVarsMap() {
public @Nullable Map<String, ? extends @Nullable Object> getVarsMap() {
return this.uriVarsMap;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -260,7 +260,7 @@ public class Jackson2ObjectMapperBuilder {
* @since 5.2.4
*/
public Jackson2ObjectMapperBuilder annotationIntrospector(
Function<AnnotationIntrospector, AnnotationIntrospector> pairingFunction) {
Function<@Nullable AnnotationIntrospector, @Nullable AnnotationIntrospector> pairingFunction) {
this.annotationIntrospector = pairingFunction.apply(this.annotationIntrospector);
return this;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,7 +56,7 @@ public class RestClientResponseException extends RestClientException {
private final @Nullable String responseCharset;
private transient @Nullable Function<ResolvableType, ?> bodyConvertFunction;
private transient @Nullable Function<ResolvableType, ? extends @Nullable Object> bodyConvertFunction;
/**
@@ -200,7 +200,7 @@ public class RestClientResponseException extends RestClientException {
* @param bodyConvertFunction the function to use
* @since 6.0
*/
public void setBodyConvertFunction(Function<ResolvableType, ?> bodyConvertFunction) {
public void setBodyConvertFunction(Function<ResolvableType, ? extends @Nullable Object> bodyConvertFunction) {
this.bodyConvertFunction = bodyConvertFunction;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,7 +99,8 @@ final class StatusHandler {
});
}
private static Function<ResolvableType, ?> initBodyConvertFunction(ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
@SuppressWarnings("NullAway")
private static Function<ResolvableType, ? extends @Nullable Object> initBodyConvertFunction(ClientHttpResponse response, byte[] body, List<HttpMessageConverter<?>> messageConverters) {
Assert.state(!CollectionUtils.isEmpty(messageConverters), "Expected message converters");
return resolvableType -> {
try {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -159,7 +159,7 @@ public class FormContentFilter extends OncePerRequestFilter {
}
@Override
public @Nullable String[] getParameterValues(String name) {
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
List<String> formParam = this.formParams.get(name);
if (formParam == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -357,7 +357,7 @@ public class HandlerMethod extends AnnotatedMethod {
* beans, and others). {@code @Controller}'s that require proxying should prefer
* class-based proxy mechanisms.
*/
protected void assertTargetBean(Method method, Object targetBean, Object[] args) {
protected void assertTargetBean(Method method, Object targetBean, @Nullable Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
@@ -369,11 +369,14 @@ public class HandlerMethod extends AnnotatedMethod {
}
}
protected String formatInvokeError(String text, Object[] args) {
protected String formatInvokeError(String text, @Nullable Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.mapToObj(i -> {
Object arg = args[i];
return (arg != null ?
"[" + i + "] [type=" +arg.getClass().getName() + "] [value=" + arg + "]" :
"[" + i + "] [null]");
})
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Controller [" + getBeanType().getName() + "]\n" +

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.jspecify.annotations.Nullable;
@@ -226,7 +227,7 @@ public class ExceptionHandlerMethodResolver {
* Return the {@link Method} mapped to the given exception type, or
* {@link #NO_MATCHING_EXCEPTION_HANDLER} if none.
*/
private @Nullable ExceptionHandlerMappingInfo getMappedMethod(Class<? extends Throwable> exceptionType, MediaType mediaType) {
private ExceptionHandlerMappingInfo getMappedMethod(Class<? extends Throwable> exceptionType, MediaType mediaType) {
List<ExceptionMapping> matches = new ArrayList<>();
for (ExceptionMapping mappingInfo : this.mappedMethods.keySet()) {
if (mappingInfo.exceptionType().isAssignableFrom(exceptionType) && mappingInfo.mediaType().isCompatibleWith(mediaType)) {
@@ -237,7 +238,7 @@ public class ExceptionHandlerMethodResolver {
if (matches.size() > 1) {
matches.sort(new ExceptionMapingComparator(exceptionType, mediaType));
}
return this.mappedMethods.get(matches.get(0));
return Objects.requireNonNull(this.mappedMethods.get(matches.get(0)));
}
else {
return NO_MATCHING_EXCEPTION_HANDLER;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ public final class HandlerMethodValidator implements MethodValidator {
@Override
public void applyArgumentValidation(
Object target, Method method, MethodParameter @Nullable [] parameters,
Object[] arguments, Class<?>[] groups) {
@Nullable Object[] arguments, Class<?>[] groups) {
MethodValidationResult result = validateArguments(target, method, parameters, arguments, groups);
if (!result.hasErrors()) {
@@ -110,7 +110,7 @@ public final class HandlerMethodValidator implements MethodValidator {
@Override
public MethodValidationResult validateArguments(
Object target, Method method, MethodParameter @Nullable [] parameters,
Object[] arguments, Class<?>[] groups) {
@Nullable Object[] arguments, Class<?>[] groups) {
return this.validationAdapter.validateArguments(target, method, parameters, arguments, groups);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -172,9 +172,9 @@ public class InvocableHandlerMethod extends HandlerMethod {
* @see #doInvoke
*/
public @Nullable Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
@Nullable Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
@Nullable Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
@@ -200,15 +200,15 @@ public class InvocableHandlerMethod extends HandlerMethod {
* <p>The resulting array will be passed into {@link #doInvoke}.
* @since 5.1.2
*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
protected @Nullable Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
@Nullable Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
@Nullable Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
@@ -239,7 +239,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
/**
* Invoke the handler method with the given argument values.
*/
protected @Nullable Object doInvoke(Object... args) throws Exception {
protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception {
Method method = getBridgedMethod();
try {
if (KotlinDetector.isKotlinReflectPresent()) {
@@ -285,7 +285,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
* instead.
* @since 6.0
*/
protected Object invokeSuspendingFunction(Method method, Object target, Object[] args) {
protected Object invokeSuspendingFunction(Method method, Object target, @Nullable Object[] args) {
Object result = CoroutinesUtils.invokeSuspendingFunction(method, target, args);
return (result instanceof Mono<?> mono ? mono.handle(KotlinDelegate::handleResult) : result);
}
@@ -297,7 +297,9 @@ public class InvocableHandlerMethod extends HandlerMethod {
private static class KotlinDelegate {
@SuppressWarnings("DataFlowIssue")
public static @Nullable Object invokeFunction(Method method, Object target, Object[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
public static @Nullable Object invokeFunction(Method method, Object target, @Nullable Object[] args) throws
InvocationTargetException, IllegalAccessException, NoSuchMethodException {
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
// For property accessors
if (function == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -127,13 +127,13 @@ final class HttpServiceMethod {
}
public @Nullable Object invoke(Object[] arguments) {
public @Nullable Object invoke(@Nullable Object[] arguments) {
HttpRequestValues.Builder requestValues = this.requestValuesInitializer.initializeRequestValuesBuilder();
applyArguments(requestValues, arguments);
return this.responseFunction.execute(requestValues.build());
}
private void applyArguments(HttpRequestValues.Builder requestValues, Object[] arguments) {
private void applyArguments(HttpRequestValues.Builder requestValues, @Nullable Object[] arguments) {
Assert.isTrue(arguments.length == this.parameters.length, "Method argument mismatch");
for (int i = 0; i < arguments.length; i++) {
Object value = arguments[i];
@@ -383,10 +383,10 @@ final class HttpServiceMethod {
}
private record ExchangeResponseFunction(
Function<HttpRequestValues, Object> responseFunction) implements ResponseFunction {
Function<HttpRequestValues, @Nullable Object> responseFunction) implements ResponseFunction {
@Override
public Object execute(HttpRequestValues requestValues) {
public @Nullable Object execute(HttpRequestValues requestValues) {
return this.responseFunction.apply(requestValues);
}
@@ -403,7 +403,7 @@ final class HttpServiceMethod {
MethodParameter param = new MethodParameter(method, -1).nestedIfOptional();
Class<?> paramType = param.getNestedParameterType();
Function<HttpRequestValues, Object> responseFunction;
Function<HttpRequestValues, @Nullable Object> responseFunction;
if (ClassUtils.isVoidType(paramType)) {
responseFunction = requestValues -> {
client.exchange(requestValues);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -233,7 +233,7 @@ public final class HttpServiceProxyFactory {
Method method = invocation.getMethod();
HttpServiceMethod httpServiceMethod = this.httpServiceMethods.get(method);
if (httpServiceMethod != null) {
Object[] arguments = KotlinDetector.isSuspendingFunction(method) ?
@Nullable Object[] arguments = KotlinDetector.isSuspendingFunction(method) ?
resolveCoroutinesArguments(invocation.getArguments()) : invocation.getArguments();
return httpServiceMethod.invoke(arguments);
}
@@ -246,7 +246,7 @@ public final class HttpServiceProxyFactory {
throw new IllegalStateException("Unexpected method invocation: " + method);
}
private static Object[] resolveCoroutinesArguments(Object[] args) {
private static Object[] resolveCoroutinesArguments(@Nullable Object[] args) {
Object[] functionArgs = new Object[args.length - 1];
System.arraycopy(args, 0, functionArgs, 0, args.length - 1);
return functionArgs;

View File

@@ -140,6 +140,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
* with a Map of variables.
* @param defaultUriVariables default URI variable values
*/
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
public void setDefaultUriVariables(@Nullable Map<String, ? extends @Nullable Object> defaultUriVariables) {
if (defaultUriVariables != null) {
if (this.defaultUriVariables == null) {
@@ -431,6 +432,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
}
@Override
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
public URI build(Map<String, ?> uriVars) {
if (!CollectionUtils.isEmpty(defaultUriVariables)) {
Map<String, Object> map = new HashMap<>(defaultUriVariables.size() + uriVars.size());
@@ -446,6 +448,7 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
}
@Override
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1126
public URI build(@Nullable Object... uriVars) {
if (ObjectUtils.isEmpty(uriVars) && !CollectionUtils.isEmpty(defaultUriVariables)) {
return build(Collections.emptyMap());