Skip to content

Commit

Permalink
Specify generic type nullness in spring-beans
Browse files Browse the repository at this point in the history
  • Loading branch information
sdeleuze committed Jan 14, 2025
1 parent f52f833 commit 928a3c7
Show file tree
Hide file tree
Showing 17 changed files with 56 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -196,7 +196,7 @@ public static <T> T instantiateClass(Constructor<T> ctor, @Nullable Object... ar
return ctor.newInstance();
}
Class<?>[] parameterTypes = ctor.getParameterTypes();
Object[] argsWithDefaultValues = new Object[args.length];
@Nullable Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
Expand Down Expand Up @@ -654,9 +654,10 @@ public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {
* @see ConstructorProperties
* @see DefaultParameterNameDiscoverer
*/
public static String[] getParameterNames(Constructor<?> ctor) {
@SuppressWarnings("NullAway") // Dataflow analysis limitation
public static @Nullable String[] getParameterNames(Constructor<?> ctor) {
ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
@Nullable String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
Assert.state(paramNames.length == ctor.getParameterCount(),
() -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -812,7 +812,7 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
return;
}
Method method = (Method) this.member;
Object[] arguments;
@Nullable Object[] arguments;
if (this.cached) {
try {
arguments = resolveCachedArguments(beanName, this.cachedMethodArguments);
Expand All @@ -838,20 +838,20 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
}
}

private Object @Nullable [] resolveCachedArguments(@Nullable String beanName, Object @Nullable [] cachedMethodArguments) {
private @Nullable Object @Nullable [] resolveCachedArguments(@Nullable String beanName, Object @Nullable [] cachedMethodArguments) {
if (cachedMethodArguments == null) {
return null;
}
Object[] arguments = new Object[cachedMethodArguments.length];
@Nullable Object[] arguments = new Object[cachedMethodArguments.length];
for (int i = 0; i < arguments.length; i++) {
arguments[i] = resolveCachedArgument(beanName, cachedMethodArguments[i]);
}
return arguments;
}

private Object @Nullable [] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
private @Nullable Object @Nullable [] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
@Nullable Object[] arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeanNames = CollectionUtils.newLinkedHashSet(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -291,7 +291,7 @@ protected boolean checkQualifier(
}
}

Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
Map<String, @Nullable Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (attributes.isEmpty() && qualifier == null) {
// If no attributes, the qualifier must be present
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
Expand Down Expand Up @@ -74,15 +74,15 @@ public interface AutowiredArguments {
* Return the arguments as an object array.
* @return the arguments as an object array
*/
Object[] toArray();
@Nullable Object[] toArray();

/**
* Factory method to create a new {@link AutowiredArguments} instance from
* the given object array.
* @param arguments the arguments
* @return a new {@link AutowiredArguments} instance
*/
static AutowiredArguments of(Object[] arguments) {
static AutowiredArguments of(@Nullable Object[] arguments) {
Assert.notNull(arguments, "'arguments' must not be null");
return () -> arguments;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -162,7 +162,7 @@ public void resolveAndInvoke(RegisteredBean registeredBean, Object instance) {
Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);
AutowireCapableBeanFactory autowireCapableBeanFactory = (AutowireCapableBeanFactory) beanFactory;
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
@Nullable Object[] arguments = new Object[argumentCount];
Set<String> autowiredBeanNames = CollectionUtils.newLinkedHashSet(argumentCount);
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < argumentCount; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -111,7 +111,7 @@ class BeanDefinitionPropertiesCodeGenerator {
this.valueCodeGenerator = ValueCodeGenerator.with(allDelegates).scoped(generatedMethods);
}


@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1128
CodeBlock generateCode(RootBeanDefinition beanDefinition) {
CodeBlock.Builder code = CodeBlock.builder();
addStatementForValue(code, beanDefinition, BeanDefinition::getScope,
Expand Down Expand Up @@ -344,22 +344,22 @@ private Object toRole(int value) {
}

private <B extends BeanDefinition, T> void addStatementForValue(
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, T> getter, String format) {
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, @Nullable T> getter, String format) {

addStatementForValue(code, beanDefinition, getter,
(defaultValue, actualValue) -> !Objects.equals(defaultValue, actualValue), format);
}

private <B extends BeanDefinition, T> void addStatementForValue(
CodeBlock.Builder code, BeanDefinition beanDefinition,
Function<B, T> getter, BiPredicate<T, T> filter, String format) {
Function<B, @Nullable T> getter, BiPredicate<T, T> filter, String format) {

addStatementForValue(code, beanDefinition, getter, filter, format, actualValue -> actualValue);
}

@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "NullAway"})
private <B extends BeanDefinition, T> void addStatementForValue(
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, T> getter,
CodeBlock.Builder code, BeanDefinition beanDefinition, Function<B, @Nullable T> getter,
BiPredicate<T, T> filter, String format, Function<T, Object> formatter) {

T defaultValue = getter.apply((B) DEFAULT_BEAN_DEFINITION);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -200,7 +200,7 @@ else if (this.generatorWithArguments != null) {
}
else {
Executable executable = this.lookup.get(registeredBean);
Object[] arguments = resolveArguments(registeredBean, executable).toArray();
@Nullable Object[] arguments = resolveArguments(registeredBean, executable).toArray();
return invokeBeanSupplier(executable, () -> (T) instantiate(registeredBean, executable, arguments));
}
}
Expand Down Expand Up @@ -242,7 +242,7 @@ AutowiredArguments resolveArguments(RegisteredBean registeredBean) {

private AutowiredArguments resolveArguments(RegisteredBean registeredBean, Executable executable) {
int parameterCount = executable.getParameterCount();
Object[] resolved = new Object[parameterCount];
@Nullable Object[] resolved = new Object[parameterCount];
Assert.isTrue(this.shortcutBeanNames == null || this.shortcutBeanNames.length == resolved.length,
() -> "'shortcuts' must contain " + resolved.length + " elements");

Expand Down Expand Up @@ -341,7 +341,7 @@ private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, V
}
}

private Object instantiate(RegisteredBean registeredBean, Executable executable, Object[] args) {
private Object instantiate(RegisteredBean registeredBean, Executable executable, @Nullable Object[] args) {
if (executable instanceof Constructor<?> constructor) {
return BeanUtils.instantiateClass(constructor, args);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -220,7 +220,7 @@ else if (value instanceof String strValue) {
return value;
}

protected void visitArray(Object[] arrayVal) {
protected void visitArray(@Nullable Object[] arrayVal) {
for (int i = 0; i < arrayVal.length; i++) {
Object elem = arrayVal[i];
Object newVal = resolveValue(elem);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -311,7 +311,7 @@ protected Constructor<Exception> determineServiceLocatorExceptionConstructor(Cla
*/
protected Exception createServiceLocatorException(Constructor<Exception> exceptionConstructor, BeansException cause) {
Class<?>[] paramTypes = exceptionConstructor.getParameterTypes();
Object[] args = new Object[paramTypes.length];
@Nullable Object[] args = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
if (String.class == paramTypes[i]) {
args[i] = cause.getMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable O
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object @Nullable [] args)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args)
throws BeanCreationException {

// Instantiate the bean.
Expand Down Expand Up @@ -753,15 +753,15 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// Fully resolve parameter names and argument values.
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Class<?>[] paramTypes = candidate.getParameterTypes();
String[] paramNames = null;
@Nullable String[] paramNames = null;
if (cav.containsNamedArgument()) {
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = CollectionUtils.newHashSet(paramTypes.length);
Object[] args = new Object[paramTypes.length];
@Nullable Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -173,7 +173,7 @@ public static Object resolveAutowiringValue(Object autowiringValue, Class<?> req
* @since 3.2.5
*/
public static Class<?> resolveReturnTypeForFactoryMethod(
Method method, Object[] args, @Nullable ClassLoader classLoader) {
Method method, @Nullable Object[] args, @Nullable ClassLoader classLoader) {

Assert.notNull(method, "Method must not be null");
Assert.notNull(args, "Argument array must not be null");
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -287,7 +287,7 @@ public <T> T resolveInnerBean(@Nullable String innerBeanName, BeanDefinition inn
}
else if (value instanceof String[] values) {
boolean actuallyResolved = false;
Object[] resolvedValues = new Object[values.length];
@Nullable Object[] resolvedValues = new Object[values.length];
for (int i = 0; i < values.length; i++) {
String originalValue = values[i];
Object resolvedValue = doEvaluate(originalValue);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -814,7 +814,7 @@ private ArgumentsHolder createArgumentArray(
/**
* Resolve the prepared arguments stored in the given bean definition.
*/
private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
private @Nullable Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
Executable executable, Object[] argsToResolve) {

TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
Expand All @@ -823,7 +823,7 @@ private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mb
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
Class<?>[] paramTypes = executable.getParameterTypes();

Object[] resolvedArgs = new Object[argsToResolve.length];
@Nullable Object[] resolvedArgs = new Object[argsToResolve.length];
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
Object argValue = argsToResolve[argIndex];
Class<?> paramType = paramTypes[argIndex];
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -357,7 +357,7 @@ public <T> T getBean(Class<T> requiredType) throws BeansException {

@SuppressWarnings("unchecked")
@Override
public <T> T getBean(Class<T> requiredType, Object @Nullable ... args) throws BeansException {
public <T> T getBean(Class<T> requiredType, @Nullable Object @Nullable ... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
Expand Down Expand Up @@ -500,7 +500,7 @@ public Stream<T> orderedStream() {
};
}

private <T> @Nullable T resolveBean(ResolvableType requiredType, Object @Nullable [] args, boolean nonUniqueAsNull) {
private <T> @Nullable T resolveBean(ResolvableType requiredType, @Nullable Object @Nullable [] args, boolean nonUniqueAsNull) {
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
Expand Down Expand Up @@ -1411,7 +1411,7 @@ public <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws Bea

@SuppressWarnings("unchecked")
private <T> @Nullable NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, Object @Nullable [] args, boolean nonUniqueAsNull) throws BeansException {
ResolvableType requiredType, @Nullable Object @Nullable [] args, boolean nonUniqueAsNull) throws BeansException {

Assert.notNull(requiredType, "Required type must not be null");
String[] candidateNames = getBeanNamesForType(requiredType);
Expand Down Expand Up @@ -1465,7 +1465,7 @@ else if (candidateNames.length > 1) {
}

private <T> @Nullable NamedBeanHolder<T> resolveNamedBean(
String beanName, ResolvableType requiredType, Object @Nullable [] args) throws BeansException {
String beanName, ResolvableType requiredType, @Nullable Object @Nullable [] args) throws BeansException {

Object bean = getBean(beanName, null, args);
if (bean instanceof NullBean) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
Expand Down Expand Up @@ -58,6 +58,7 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars


@Override
@SuppressWarnings("NullAway") // Dataflow analysis limitation
public final @Nullable BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 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.
Expand Down Expand Up @@ -127,7 +127,7 @@ public StringArrayPropertyEditor(

@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] array = StringUtils.delimitedListToStringArray(text, this.separator, this.charsToDelete);
@Nullable String[] array = StringUtils.delimitedListToStringArray(text, this.separator, this.charsToDelete);
if (this.emptyArrayAsNull && array.length == 0) {
setValue(null);
}
Expand Down
Loading

0 comments on commit 928a3c7

Please sign in to comment.