Refine null-safety in more modules

This commit refines the null-safety in:
 - spring-jdbc
 - spring-r2dbc
 - spring-orm
 - spring-beans
 - spring-aop

See gh-32475
This commit is contained in:
Sébastien Deleuze 2024-03-26 09:46:34 +01:00
parent dea31dd55e
commit 1b563f8ba4
40 changed files with 69 additions and 17 deletions

View File

@ -22,6 +22,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@ -38,6 +39,7 @@ class AspectJAdvisorBeanRegistrationAotProcessor implements BeanRegistrationAotP
@Override
@Nullable
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
if (aspectjPresent) {
Class<?> beanClass = registeredBean.getBeanClass();

View File

@ -23,6 +23,7 @@ import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.lang.Nullable;
/**
* {@link BeanDefinitionParser} responsible for parsing the
@ -51,6 +52,7 @@ class SpringConfiguredBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
if (!parserContext.getRegistry().containsBeanDefinition(BEAN_CONFIGURER_ASPECT_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();

View File

@ -270,6 +270,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
}
@Override
@Nullable
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
@ -311,6 +312,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
@Nullable
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);

View File

@ -81,6 +81,7 @@ public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
* @see #setBeanNames(String...)
*/
@Override
@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
return (isSupportedBeanName(beanClass, beanName) ?
super.getCustomTargetSource(beanClass, beanName) : null);

View File

@ -53,6 +53,7 @@ class ScopedProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProc
@Override
@Nullable
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
if (beanClass.equals(ScopedProxyFactoryBean.class)) {

View File

@ -117,6 +117,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig
@Override
@Nullable
public Object getObject() {
if (this.proxy == null) {
throw new FactoryBeanNotInitializedException();
@ -125,6 +126,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig
}
@Override
@Nullable
public Class<?> getObjectType() {
if (this.proxy != null) {
return this.proxy.getClass();

View File

@ -69,7 +69,7 @@ public class BeanInstantiationException extends FatalBeanException {
* @param cause the root cause
* @since 4.3
*/
public BeanInstantiationException(Constructor<?> constructor, String msg, @Nullable Throwable cause) {
public BeanInstantiationException(Constructor<?> constructor, @Nullable String msg, @Nullable Throwable cause) {
super("Failed to instantiate [" + constructor.getDeclaringClass().getName() + "]: " + msg, cause);
this.beanClass = constructor.getDeclaringClass();
this.constructor = constructor;
@ -84,7 +84,7 @@ public class BeanInstantiationException extends FatalBeanException {
* @param cause the root cause
* @since 4.3
*/
public BeanInstantiationException(Method constructingMethod, String msg, @Nullable Throwable cause) {
public BeanInstantiationException(Method constructingMethod, @Nullable String msg, @Nullable Throwable cause) {
super("Failed to instantiate [" + constructingMethod.getReturnType().getName() + "]: " + msg, cause);
this.beanClass = constructingMethod.getReturnType();
this.constructor = null;

View File

@ -18,6 +18,8 @@ package org.springframework.beans;
import java.beans.PropertyChangeEvent;
import org.springframework.lang.Nullable;
/**
* Thrown when a bean property getter or setter method throws an exception,
* analogous to an InvocationTargetException.
@ -38,7 +40,7 @@ public class MethodInvocationException extends PropertyAccessException {
* @param propertyChangeEvent the PropertyChangeEvent that resulted in an exception
* @param cause the Throwable raised by the invoked method
*/
public MethodInvocationException(PropertyChangeEvent propertyChangeEvent, Throwable cause) {
public MethodInvocationException(PropertyChangeEvent propertyChangeEvent, @Nullable Throwable cause) {
super(propertyChangeEvent, "Property '" + propertyChangeEvent.getPropertyName() + "' threw exception", cause);
}

View File

@ -94,7 +94,7 @@ public class BeanCreationException extends FatalBeanException {
* @param beanName the name of the bean requested
* @param msg the detail message
*/
public BeanCreationException(@Nullable String resourceDescription, @Nullable String beanName, String msg) {
public BeanCreationException(@Nullable String resourceDescription, @Nullable String beanName, @Nullable String msg) {
super("Error creating bean with name '" + beanName + "'" +
(resourceDescription != null ? " defined in " + resourceDescription : "") + ": " + msg);
this.resourceDescription = resourceDescription;
@ -110,7 +110,7 @@ public class BeanCreationException extends FatalBeanException {
* @param msg the detail message
* @param cause the root cause
*/
public BeanCreationException(@Nullable String resourceDescription, String beanName, String msg, Throwable cause) {
public BeanCreationException(@Nullable String resourceDescription, String beanName, @Nullable String msg, Throwable cause) {
this(resourceDescription, beanName, msg);
initCause(cause);
}

View File

@ -44,7 +44,7 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
* @param msg the detail message
*/
public UnsatisfiedDependencyException(
@Nullable String resourceDescription, @Nullable String beanName, String propertyName, String msg) {
@Nullable String resourceDescription, @Nullable String beanName, String propertyName, @Nullable String msg) {
super(resourceDescription, beanName,
"Unsatisfied dependency expressed through bean property '" + propertyName + "'" +
@ -75,7 +75,7 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
* @since 4.3
*/
public UnsatisfiedDependencyException(
@Nullable String resourceDescription, @Nullable String beanName, @Nullable InjectionPoint injectionPoint, String msg) {
@Nullable String resourceDescription, @Nullable String beanName, @Nullable InjectionPoint injectionPoint, @Nullable String msg) {
super(resourceDescription, beanName,
"Unsatisfied dependency expressed through " + injectionPoint +

View File

@ -37,6 +37,7 @@ import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.javapoet.AnnotationSpec;
import org.springframework.javapoet.CodeBlock;
import org.springframework.lang.Nullable;
/**
* Code generator {@link Delegate} for common bean definition property values.
@ -101,6 +102,7 @@ abstract class BeanDefinitionPropertyValueCodeGeneratorDelegates {
private static final CodeBlock EMPTY_RESULT = CodeBlock.of("$T.ofEntries()", ManagedMap.class);
@Override
@Nullable
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof ManagedMap<?, ?> managedMap) {
return generateManagedMapCode(valueCodeGenerator, managedMap);
@ -137,6 +139,7 @@ abstract class BeanDefinitionPropertyValueCodeGeneratorDelegates {
private static class LinkedHashMapDelegate extends MapDelegate {
@Override
@Nullable
protected CodeBlock generateMapCode(ValueCodeGenerator valueCodeGenerator, Map<?, ?> map) {
GeneratedMethods generatedMethods = valueCodeGenerator.getGeneratedMethods();
if (map instanceof LinkedHashMap<?, ?> && generatedMethods != null) {
@ -172,6 +175,7 @@ abstract class BeanDefinitionPropertyValueCodeGeneratorDelegates {
private static class BeanReferenceDelegate implements Delegate {
@Override
@Nullable
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof RuntimeBeanReference runtimeBeanReference &&
runtimeBeanReference.getBeanType() != null) {
@ -193,6 +197,7 @@ abstract class BeanDefinitionPropertyValueCodeGeneratorDelegates {
private static class TypedStringValueDelegate implements Delegate {
@Override
@Nullable
public CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
if (value instanceof TypedStringValue typedStringValue) {
return generateTypeStringValueCode(valueCodeGenerator, typedStringValue);

View File

@ -151,6 +151,7 @@ public abstract class AbstractFactoryBean<T>
* @see #getEarlySingletonInterfaces()
*/
@Override
@Nullable
public final T getObject() throws Exception {
if (isSingleton()) {
return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());

View File

@ -226,6 +226,7 @@ public class FieldRetrievingFactoryBean
}
@Override
@Nullable
public Class<?> getObjectType() {
return (this.fieldObject != null ? this.fieldObject.getType() : null);
}

View File

@ -136,6 +136,7 @@ public class MethodInvokingFactoryBean extends MethodInvokingBean implements Fac
* or {@code null} if not known in advance.
*/
@Override
@Nullable
public Class<?> getObjectType() {
if (!isPrepared()) {
// Not fully initialized yet -> return null to indicate "not known yet".

View File

@ -224,6 +224,7 @@ public class PropertyPathFactoryBean implements FactoryBean<Object>, BeanNameAwa
}
@Override
@Nullable
public Class<?> getObjectType() {
return this.resultType;
}

View File

@ -335,6 +335,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
}
@Override
@Nullable
public Class<?> getObjectType() {
return this.serviceLocatorInterface;
}

View File

@ -241,6 +241,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
}
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
// Cast is safe, as CallbackFilter filters are used selectively.
LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);

View File

@ -1434,6 +1434,7 @@ class ConstructorResolver {
}
@Override
@Nullable
public Object resolveShortcut(BeanFactory beanFactory) {
String shortcut = this.shortcut;
return (shortcut != null ? beanFactory.getBean(shortcut, getDependencyType()) : null);

View File

@ -342,7 +342,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
void logDestroyMethodException(Method destroyMethod, Throwable ex) {
void logDestroyMethodException(Method destroyMethod, @Nullable Throwable ex) {
if (logger.isWarnEnabled()) {
String msg = "Custom destroy method '" + destroyMethod.getName() + "' on bean with name '" +
this.beanName + "' propagated an exception";

View File

@ -83,6 +83,7 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
return after.applyWithException(registeredBean, InstanceSupplier.this.get(registeredBean));
}
@Override
@Nullable
public Method getFactoryMethod() {
return InstanceSupplier.this.getFactoryMethod();
}
@ -126,6 +127,7 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
return supplier.getWithException();
}
@Override
@Nullable
public Method getFactoryMethod() {
return factoryMethod;
}

View File

@ -277,6 +277,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
@Override
@Nullable
public String getParentName() {
return null;
}

View File

@ -232,11 +232,13 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
}
@Override
@Nullable
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getType(name, true);
}
@Override
@Nullable
public Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException {
String beanName = BeanFactoryUtils.transformedBeanName(name);

View File

@ -136,7 +136,7 @@ public class MethodInvoker {
* Set arguments for the method invocation. If this property is not set,
* or the Object array is of length 0, a method with no arguments is assumed.
*/
public void setArguments(Object... arguments) {
public void setArguments(@Nullable Object... arguments) {
this.arguments = arguments;
}

View File

@ -137,7 +137,7 @@ public abstract class ReflectionUtils {
* @param ex the exception to rethrow
* @throws RuntimeException the rethrown exception
*/
public static void rethrowRuntimeException(Throwable ex) {
public static void rethrowRuntimeException(@Nullable Throwable ex) {
if (ex instanceof RuntimeException runtimeException) {
throw runtimeException;
}
@ -158,7 +158,7 @@ public abstract class ReflectionUtils {
* @param throwable the exception to rethrow
* @throws Exception the rethrown exception (in case of a checked exception)
*/
public static void rethrowException(Throwable throwable) throws Exception {
public static void rethrowException(@Nullable Throwable throwable) throws Exception {
if (throwable instanceof Exception exception) {
throw exception;
}

View File

@ -19,6 +19,7 @@ package org.springframework.jdbc;
import java.sql.SQLException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.lang.Nullable;
/**
* Exception thrown when SQL specified is invalid. Such exceptions always have
@ -52,6 +53,7 @@ public class BadSqlGrammarException extends InvalidDataAccessResourceUsageExcept
/**
* Return the wrapped SQLException.
*/
@Nullable
public SQLException getSQLException() {
return (SQLException) getCause();
}

View File

@ -64,6 +64,7 @@ public class InvalidResultSetAccessException extends InvalidDataAccessResourceUs
/**
* Return the wrapped SQLException.
*/
@Nullable
public SQLException getSQLException() {
return (SQLException) getCause();
}

View File

@ -19,6 +19,7 @@ package org.springframework.jdbc;
import java.sql.SQLWarning;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;
/**
* Exception thrown when we're not ignoring {@link java.sql.SQLWarning SQLWarnings}.
@ -49,6 +50,7 @@ public class SQLWarningException extends UncategorizedDataAccessException {
* Return the underlying {@link SQLWarning}.
* @since 5.3.29
*/
@Nullable
public SQLWarning getSQLWarning() {
return (SQLWarning) getCause();
}
@ -58,6 +60,7 @@ public class SQLWarningException extends UncategorizedDataAccessException {
* @deprecated as of 5.3.29, in favor of {@link #getSQLWarning()}
*/
@Deprecated(since = "5.3.29")
@Nullable
public SQLWarning SQLWarning() {
return getSQLWarning();
}

View File

@ -53,6 +53,7 @@ public class UncategorizedSQLException extends UncategorizedDataAccessException
/**
* Return the underlying SQLException.
*/
@Nullable
public SQLException getSQLException() {
return (SQLException) getCause();
}

View File

@ -907,11 +907,13 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
@Deprecated
@Override
@Nullable
public <T> T queryForObject(String sql, @Nullable Object[] args, Class<T> requiredType) throws DataAccessException {
return queryForObject(sql, args, getSingleColumnRowMapper(requiredType));
}
@Override
@Nullable
public <T> T queryForObject(String sql, Class<T> requiredType, @Nullable Object... args) throws DataAccessException {
return queryForObject(sql, args, getSingleColumnRowMapper(requiredType));
}

View File

@ -20,6 +20,7 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@ -34,9 +35,11 @@ import org.springframework.util.Assert;
*/
public abstract class AbstractDataFieldMaxValueIncrementer implements DataFieldMaxValueIncrementer, InitializingBean {
@Nullable
private DataSource dataSource;
/** The name of the sequence/table containing the sequence. */
@Nullable
private String incrementerName;
/** The length to which a string result should be pre-pended with zeroes. */

View File

@ -42,7 +42,7 @@ public class ObjectOptimisticLockingFailureException extends OptimisticLockingFa
* @param msg the detail message
* @param cause the source exception
*/
public ObjectOptimisticLockingFailureException(String msg, Throwable cause) {
public ObjectOptimisticLockingFailureException(@Nullable String msg, Throwable cause) {
super(msg, cause);
this.persistentClass = null;
this.identifier = null;
@ -123,7 +123,7 @@ public class ObjectOptimisticLockingFailureException extends OptimisticLockingFa
* @param cause the source exception
*/
public ObjectOptimisticLockingFailureException(
String persistentClassName, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
String persistentClassName, @Nullable Object identifier, @Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClassName;

View File

@ -42,7 +42,7 @@ public class ObjectRetrievalFailureException extends DataRetrievalFailureExcepti
* @param msg the detail message
* @param cause the source exception
*/
public ObjectRetrievalFailureException(String msg, Throwable cause) {
public ObjectRetrievalFailureException(@Nullable String msg, Throwable cause) {
super(msg, cause);
this.persistentClass = null;
this.identifier = null;
@ -97,7 +97,7 @@ public class ObjectRetrievalFailureException extends DataRetrievalFailureExcepti
* @param cause the source exception
*/
public ObjectRetrievalFailureException(
String persistentClassName, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
String persistentClassName, @Nullable Object identifier, @Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClassName;

View File

@ -21,6 +21,7 @@ import java.sql.SQLException;
import org.hibernate.JDBCException;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;
/**
* Hibernate-specific subclass of UncategorizedDataAccessException,
@ -48,6 +49,7 @@ public class HibernateJdbcException extends UncategorizedDataAccessException {
/**
* Return the SQL that led to the problem.
*/
@Nullable
public String getSql() {
return ((JDBCException) getCause()).getSQL();
}

View File

@ -19,6 +19,7 @@ package org.springframework.orm.hibernate5;
import org.hibernate.QueryException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.lang.Nullable;
/**
* Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
@ -38,6 +39,7 @@ public class HibernateQueryException extends InvalidDataAccessResourceUsageExcep
/**
* Return the HQL query string that was invalid.
*/
@Nullable
public String getQueryString() {
return ((QueryException) getCause()).getQueryString();
}

View File

@ -22,6 +22,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.lang.Nullable;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.orm.hibernate5.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@ -72,7 +73,7 @@ class AsyncRequestInterceptor implements CallableProcessingInterceptor, Deferred
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
public <T> void postProcess(NativeWebRequest request, Callable<T> task, @Nullable Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}

View File

@ -22,6 +22,7 @@ import jakarta.persistence.EntityManagerFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@ -72,7 +73,7 @@ class AsyncRequestInterceptor implements CallableProcessingInterceptor, Deferred
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
public <T> void postProcess(NativeWebRequest request, Callable<T> task, @Nullable Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.emFactory);
}

View File

@ -19,6 +19,7 @@ package org.springframework.r2dbc;
import io.r2dbc.spi.R2dbcException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.lang.Nullable;
/**
* Exception thrown when SQL specified is invalid. Such exceptions always have a
@ -52,6 +53,7 @@ public class BadSqlGrammarException extends InvalidDataAccessResourceUsageExcept
/**
* Return the wrapped {@link R2dbcException}.
*/
@Nullable
public R2dbcException getR2dbcException() {
return (R2dbcException) getCause();
}

View File

@ -51,6 +51,7 @@ public class UncategorizedR2dbcException extends UncategorizedDataAccessExceptio
/**
* Return the wrapped {@link R2dbcException}.
*/
@Nullable
public R2dbcException getR2dbcException() {
return (R2dbcException) getCause();
}

View File

@ -448,6 +448,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T getAttribute(Option<T> option) {
return (T) doGetValue(option);
}

View File

@ -129,6 +129,7 @@ public final class BindMarkersFactoryResolver {
@Override
@Nullable
public BindMarkersFactory getBindMarkers(ConnectionFactory connectionFactory) {
ConnectionFactoryMetadata metadata = connectionFactory.getMetadata();
BindMarkersFactory r2dbcDialect = BUILTIN.get(metadata.getName());