From bd405756ab22d97608efc74070101fbdb76b02ca Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 23 Jun 2026 11:55:58 +0200 Subject: [PATCH] Avoid "NullAway.Init" suppression in favor of explicit field handling Closes gh-36961 --- ...ntiationModelAwarePointcutAdvisorImpl.java | 10 +- .../AbstractRefreshableTargetSource.java | 7 +- .../beans/PropertyEditorRegistrySupport.java | 105 +++++++++--------- .../factory/config/AbstractFactoryBean.java | 5 +- .../config/PropertyPathFactoryBean.java | 23 ++-- .../config/AbstractJCacheConfiguration.java | 3 +- .../AbstractCachingConfiguration.java | 12 +- .../MergedAnnotationPredicates.java | 5 +- .../AbstractColumnMaxValueIncrementer.java | 9 +- .../AbstractDataFieldMaxValueIncrementer.java | 28 +++-- ...ractIdentityColumnMaxValueIncrementer.java | 7 +- .../AbstractSequenceMaxValueIncrementer.java | 7 +- .../incrementer/MySQLMaxValueIncrementer.java | 9 +- .../SqliteMaxValueIncrementer.java | 7 +- .../AbstractMultipartHttpServletRequest.java | 5 +- .../DefaultMultipartHttpServletRequest.java | 11 +- .../StandardMultipartHttpServletRequest.java | 7 +- .../server/adapter/HttpWebHandlerAdapter.java | 11 +- 18 files changed, 140 insertions(+), 131 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java index 98ed619760e..fd5cca68a90 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java @@ -75,11 +75,9 @@ final class InstantiationModelAwarePointcutAdvisorImpl private @Nullable Advice instantiatedAdvice; - @SuppressWarnings("NullAway.Init") - private Boolean isBeforeAdvice; + private @Nullable Boolean isBeforeAdvice; - @SuppressWarnings("NullAway.Init") - private Boolean isAfterAdvice; + private @Nullable Boolean isAfterAdvice; public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, @@ -198,7 +196,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl if (this.isBeforeAdvice == null) { determineAdviceType(); } - return this.isBeforeAdvice; + return (this.isBeforeAdvice == Boolean.TRUE); } @Override @@ -206,7 +204,7 @@ final class InstantiationModelAwarePointcutAdvisorImpl if (this.isAfterAdvice == null) { determineAdviceType(); } - return this.isAfterAdvice; + return (this.isAfterAdvice == Boolean.TRUE); } /** diff --git a/spring-aop/src/main/java/org/springframework/aop/target/dynamic/AbstractRefreshableTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/dynamic/AbstractRefreshableTargetSource.java index 88dc98c65d1..b7754b97aad 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/dynamic/AbstractRefreshableTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/dynamic/AbstractRefreshableTargetSource.java @@ -42,8 +42,7 @@ public abstract class AbstractRefreshableTargetSource implements TargetSource, R /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - @SuppressWarnings("NullAway.Init") - protected Object targetObject; + protected @Nullable Object targetObject; private long refreshCheckDelay = -1; @@ -66,11 +65,11 @@ public abstract class AbstractRefreshableTargetSource implements TargetSource, R @Override - public synchronized Class getTargetClass() { + public synchronized @Nullable Class getTargetClass() { if (this.targetObject == null) { refresh(); } - return this.targetObject.getClass(); + return (this.targetObject != null ? this.targetObject.getClass() : null); } @Override diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java index e26d9c80095..da6b9232919 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java @@ -100,8 +100,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { private @Nullable PropertyEditorRegistrar defaultEditorRegistrar; - @SuppressWarnings("NullAway.Init") - private Map, PropertyEditor> defaultEditors; + private @Nullable Map, PropertyEditor> defaultEditors; private @Nullable Map, PropertyEditor> overriddenDefaultEditors; @@ -201,7 +200,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { } } if (this.defaultEditors == null) { - createDefaultEditors(); + this.defaultEditors = createDefaultEditors(); } return this.defaultEditors.get(requiredType); } @@ -209,75 +208,77 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { /** * Actually register the default editors for this registry instance. */ - private void createDefaultEditors() { - this.defaultEditors = new HashMap<>(64); + private Map, PropertyEditor> createDefaultEditors() { + Map, PropertyEditor> defaultEditors = new HashMap<>(64); // Simple editors, without parameterization capabilities. // The JDK does not contain a default editor for any of these target types. - this.defaultEditors.put(Charset.class, new CharsetEditor()); - this.defaultEditors.put(Class.class, new ClassEditor()); - this.defaultEditors.put(Class[].class, new ClassArrayEditor()); - this.defaultEditors.put(Currency.class, new CurrencyEditor()); - this.defaultEditors.put(File.class, new FileEditor()); - this.defaultEditors.put(InputStream.class, new InputStreamEditor()); - this.defaultEditors.put(InputSource.class, new InputSourceEditor()); - this.defaultEditors.put(Locale.class, new LocaleEditor()); - this.defaultEditors.put(Path.class, new PathEditor()); - this.defaultEditors.put(Pattern.class, new PatternEditor()); - this.defaultEditors.put(Properties.class, new PropertiesEditor()); - this.defaultEditors.put(Reader.class, new ReaderEditor()); - this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); - this.defaultEditors.put(TimeZone.class, new TimeZoneEditor()); - this.defaultEditors.put(URI.class, new URIEditor()); - this.defaultEditors.put(URL.class, new URLEditor()); - this.defaultEditors.put(UUID.class, new UUIDEditor()); - this.defaultEditors.put(ZoneId.class, new ZoneIdEditor()); + defaultEditors.put(Charset.class, new CharsetEditor()); + defaultEditors.put(Class.class, new ClassEditor()); + defaultEditors.put(Class[].class, new ClassArrayEditor()); + defaultEditors.put(Currency.class, new CurrencyEditor()); + defaultEditors.put(File.class, new FileEditor()); + defaultEditors.put(InputStream.class, new InputStreamEditor()); + defaultEditors.put(InputSource.class, new InputSourceEditor()); + defaultEditors.put(Locale.class, new LocaleEditor()); + defaultEditors.put(Path.class, new PathEditor()); + defaultEditors.put(Pattern.class, new PatternEditor()); + defaultEditors.put(Properties.class, new PropertiesEditor()); + defaultEditors.put(Reader.class, new ReaderEditor()); + defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); + defaultEditors.put(TimeZone.class, new TimeZoneEditor()); + defaultEditors.put(URI.class, new URIEditor()); + defaultEditors.put(URL.class, new URLEditor()); + defaultEditors.put(UUID.class, new UUIDEditor()); + defaultEditors.put(ZoneId.class, new ZoneIdEditor()); // Default instances of collection editors. // Can be overridden by registering custom instances of those as custom editors. - this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); - this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); - this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); - this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); - this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); + defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); + defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); + defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); + defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); + defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); // Default editors for primitive arrays. - this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); - this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); + defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); + defaultEditors.put(char[].class, new CharArrayPropertyEditor()); // The JDK does not contain a default editor for char! - this.defaultEditors.put(char.class, new CharacterEditor(false)); - this.defaultEditors.put(Character.class, new CharacterEditor(true)); + defaultEditors.put(char.class, new CharacterEditor(false)); + defaultEditors.put(Character.class, new CharacterEditor(true)); // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor. - this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); - this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); + defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); + defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); // The JDK does not contain default editors for number wrapper types! // Override JDK primitive number editors with our own CustomNumberEditor. - this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); - this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); - this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); - this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); - this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); - this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); - this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); - this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); - this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); - this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); - this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); - this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); - this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); - this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); + defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); + defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); + defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); + defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); + defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); + defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); + defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); + defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); + defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); + defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); + defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); + defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); + defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); + defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); // Only register config value editors if explicitly requested. if (this.configValueEditorsActive) { StringArrayPropertyEditor sae = new StringArrayPropertyEditor(); - this.defaultEditors.put(String[].class, sae); - this.defaultEditors.put(short[].class, sae); - this.defaultEditors.put(int[].class, sae); - this.defaultEditors.put(long[].class, sae); + defaultEditors.put(String[].class, sae); + defaultEditors.put(short[].class, sae); + defaultEditors.put(int[].class, sae); + defaultEditors.put(long[].class, sae); } + + return defaultEditors; } /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java index 308f8ecb340..50f7f4f766d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java @@ -74,8 +74,7 @@ public abstract class AbstractFactoryBean private boolean initialized = false; - @SuppressWarnings("NullAway.Init") - private T singletonInstance; + private @Nullable T singletonInstance; private @Nullable T earlySingletonInstance; @@ -147,7 +146,7 @@ public abstract class AbstractFactoryBean * @see #getEarlySingletonInterfaces() */ @Override - public final T getObject() throws Exception { + public final @Nullable T getObject() throws Exception { if (isSingleton()) { return (this.initialized ? this.singletonInstance : getEarlySingletonInstance()); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java index 9ec450314f4..4ee7cc9e70b 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java @@ -89,15 +89,13 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa private @Nullable BeanWrapper targetBeanWrapper; - @SuppressWarnings("NullAway.Init") - private String targetBeanName; + private @Nullable String targetBeanName; private @Nullable String propertyPath; private @Nullable Class resultType; - @SuppressWarnings("NullAway.Init") - private String beanName; + private @Nullable String beanName; private @Nullable BeanFactory beanFactory; @@ -160,25 +158,27 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; + String targetBeanName = this.targetBeanName; - if (this.targetBeanWrapper != null && this.targetBeanName != null) { + if (this.targetBeanWrapper != null && targetBeanName != null) { throw new IllegalArgumentException("Specify either 'targetObject' or 'targetBeanName', not both"); } - if (this.targetBeanWrapper == null && this.targetBeanName == null) { + if (this.targetBeanWrapper == null && targetBeanName == null) { if (this.propertyPath != null) { throw new IllegalArgumentException( "Specify 'targetObject' or 'targetBeanName' in combination with 'propertyPath'"); } // No other properties specified: check bean name. - int dotIndex = (this.beanName != null ? this.beanName.indexOf('.') : -1); - if (dotIndex == -1) { + int dotIndex; + if (this.beanName == null || (dotIndex = this.beanName.indexOf('.')) <= 0) { throw new IllegalArgumentException( "Neither 'targetObject' nor 'targetBeanName' specified, and PropertyPathFactoryBean " + "bean name '" + this.beanName + "' does not follow 'beanName.property' syntax"); } - this.targetBeanName = this.beanName.substring(0, dotIndex); + targetBeanName = this.beanName.substring(0, dotIndex); + this.targetBeanName = targetBeanName; this.propertyPath = this.beanName.substring(dotIndex + 1); } @@ -187,9 +187,10 @@ public class PropertyPathFactoryBean implements FactoryBean, BeanNameAwa throw new IllegalArgumentException("'propertyPath' is required"); } - if (this.targetBeanWrapper == null && this.beanFactory.isSingleton(this.targetBeanName)) { + if (this.targetBeanWrapper == null && StringUtils.hasLength(targetBeanName) && + this.beanFactory.isSingleton(targetBeanName)) { // Eagerly fetch singleton target bean, and determine result type. - Object bean = this.beanFactory.getBean(this.targetBeanName); + Object bean = this.beanFactory.getBean(targetBeanName); this.targetBeanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean); this.resultType = this.targetBeanWrapper.getPropertyType(this.propertyPath); } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java index 6b997bbaf3d..e0d4f540575 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/config/AbstractJCacheConfiguration.java @@ -41,8 +41,7 @@ import org.springframework.context.annotation.Role; @Configuration(proxyBeanMethods = false) public abstract class AbstractJCacheConfiguration extends AbstractCachingConfiguration { - @SuppressWarnings("NullAway.Init") - protected Supplier<@Nullable CacheResolver> exceptionCacheResolver; + protected @Nullable Supplier<@Nullable CacheResolver> exceptionCacheResolver; @Override diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java b/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java index 087699289e8..280680cda45 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/AbstractCachingConfiguration.java @@ -50,17 +50,13 @@ public abstract class AbstractCachingConfiguration implements ImportAware { protected @Nullable AnnotationAttributes enableCaching; - @SuppressWarnings("NullAway.Init") - protected Supplier<@Nullable CacheManager> cacheManager; + protected @Nullable Supplier<@Nullable CacheManager> cacheManager; - @SuppressWarnings("NullAway.Init") - protected Supplier<@Nullable CacheResolver> cacheResolver; + protected @Nullable Supplier<@Nullable CacheResolver> cacheResolver; - @SuppressWarnings("NullAway.Init") - protected Supplier<@Nullable KeyGenerator> keyGenerator; + protected @Nullable Supplier<@Nullable KeyGenerator> keyGenerator; - @SuppressWarnings("NullAway.Init") - protected Supplier<@Nullable CacheErrorHandler> errorHandler; + protected @Nullable Supplier<@Nullable CacheErrorHandler> errorHandler; @Override diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotationPredicates.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotationPredicates.java index 4dd1a745533..7e6a08b859a 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotationPredicates.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotationPredicates.java @@ -23,6 +23,8 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -124,8 +126,7 @@ public abstract class MergedAnnotationPredicates { private boolean hasLastValue; - @SuppressWarnings("NullAway.Init") - private Object lastValue; + private @Nullable Object lastValue; FirstRunOfPredicate(Function, ?> valueExtractor) { Assert.notNull(valueExtractor, "Value extractor must not be null"); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractColumnMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractColumnMaxValueIncrementer.java index 30147c0c2b2..56d30e6d97e 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractColumnMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractColumnMaxValueIncrementer.java @@ -18,6 +18,8 @@ package org.springframework.jdbc.support.incrementer; import javax.sql.DataSource; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -31,7 +33,7 @@ import org.springframework.util.Assert; public abstract class AbstractColumnMaxValueIncrementer extends AbstractDataFieldMaxValueIncrementer { /** The name of the column for this sequence. */ - private String columnName; + private @Nullable String columnName; /** The number of keys buffered in a cache. */ private int cacheSize = 1; @@ -43,7 +45,6 @@ public abstract class AbstractColumnMaxValueIncrementer extends AbstractDataFiel * @see #setIncrementerName * @see #setColumnName */ - @SuppressWarnings("NullAway.Init") public AbstractColumnMaxValueIncrementer() { } @@ -63,14 +64,14 @@ public abstract class AbstractColumnMaxValueIncrementer extends AbstractDataFiel /** * Set the name of the column in the sequence table. */ - public void setColumnName(String columnName) { + public void setColumnName(@Nullable String columnName) { this.columnName = columnName; } /** * Return the name of the column in the sequence table. */ - public String getColumnName() { + public @Nullable String getColumnName() { return this.columnName; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractDataFieldMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractDataFieldMaxValueIncrementer.java index 2792d23dda5..a1f36831baa 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractDataFieldMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractDataFieldMaxValueIncrementer.java @@ -18,6 +18,8 @@ package org.springframework.jdbc.support.incrementer; import javax.sql.DataSource; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; import org.springframework.util.Assert; @@ -34,12 +36,10 @@ import org.springframework.util.Assert; */ public abstract class AbstractDataFieldMaxValueIncrementer implements DataFieldMaxValueIncrementer, InitializingBean { - @SuppressWarnings("NullAway.Init") - private DataSource dataSource; + private @Nullable DataSource dataSource; /** The name of the sequence/table containing the sequence. */ - @SuppressWarnings("NullAway.Init") - private String incrementerName; + private @Nullable String incrementerName; /** The length to which a string result should be prepended with zeroes. */ protected int paddingLength = 0; @@ -69,28 +69,40 @@ public abstract class AbstractDataFieldMaxValueIncrementer implements DataFieldM /** * Set the data source to retrieve the value from. */ - public void setDataSource(DataSource dataSource) { + public void setDataSource(@Nullable DataSource dataSource) { this.dataSource = dataSource; } /** * Return the data source to retrieve the value from. */ - public DataSource getDataSource() { + public @Nullable DataSource getDataSource() { return this.dataSource; } + /** + * Obtain the {@code DataSource} for actual use. + * @return the DataSource (never {@code null}) + * @throws IllegalStateException in case of no DataSource set + * @since 7.1 + */ + protected DataSource obtainDataSource() { + DataSource dataSource = getDataSource(); + Assert.state(dataSource != null, "No DataSource set"); + return dataSource; + } + /** * Set the name of the sequence/table. */ - public void setIncrementerName(String incrementerName) { + public void setIncrementerName(@Nullable String incrementerName) { this.incrementerName = incrementerName; } /** * Return the name of the sequence/table. */ - public String getIncrementerName() { + public @Nullable String getIncrementerName() { return this.incrementerName; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java index fd65f94a3e8..e7107a4e465 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java @@ -91,11 +91,12 @@ public abstract class AbstractIdentityColumnMaxValueIncrementer extends Abstract * are performed on the same connection (otherwise we can't be sure that @@identity * returns the correct value) */ - Connection con = DataSourceUtils.getConnection(getDataSource()); + DataSource dataSource = obtainDataSource(); + Connection con = DataSourceUtils.getConnection(dataSource); Statement stmt = null; try { stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); + DataSourceUtils.applyTransactionTimeout(stmt, dataSource); this.valueCache = new long[getCacheSize()]; this.nextValueIndex = 0; for (int i = 0; i < getCacheSize(); i++) { @@ -118,7 +119,7 @@ public abstract class AbstractIdentityColumnMaxValueIncrementer extends Abstract } finally { JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); + DataSourceUtils.releaseConnection(con, dataSource); } } Assert.state(this.valueCache != null, "The cache of values can't be null"); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractSequenceMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractSequenceMaxValueIncrementer.java index b1fd3b4ef14..b7184bbc033 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractSequenceMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractSequenceMaxValueIncrementer.java @@ -61,12 +61,13 @@ public abstract class AbstractSequenceMaxValueIncrementer extends AbstractDataFi */ @Override protected long getNextKey() throws DataAccessException { - Connection con = DataSourceUtils.getConnection(getDataSource()); + DataSource dataSource = obtainDataSource(); + Connection con = DataSourceUtils.getConnection(dataSource); Statement stmt = null; ResultSet rs = null; try { stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); + DataSourceUtils.applyTransactionTimeout(stmt, dataSource); rs = stmt.executeQuery(getSequenceQuery()); if (rs.next()) { return rs.getLong(1); @@ -81,7 +82,7 @@ public abstract class AbstractSequenceMaxValueIncrementer extends AbstractDataFi finally { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); + DataSourceUtils.releaseConnection(con, dataSource); } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java index 7c364586dac..23bc18812a6 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java @@ -127,20 +127,21 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer Connection con = null; Statement stmt = null; boolean mustRestoreAutoCommit = false; + DataSource dataSource = obtainDataSource(); try { if (this.useNewConnection) { - con = getDataSource().getConnection(); + con = dataSource.getConnection(); if (con.getAutoCommit()) { mustRestoreAutoCommit = true; con.setAutoCommit(false); } } else { - con = DataSourceUtils.getConnection(getDataSource()); + con = DataSourceUtils.getConnection(dataSource); } stmt = con.createStatement(); if (!this.useNewConnection) { - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); + DataSourceUtils.applyTransactionTimeout(stmt, dataSource); } // Increment the sequence column... String columnName = getColumnName(); @@ -185,7 +186,7 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer JdbcUtils.closeConnection(con); } else { - DataSourceUtils.releaseConnection(con, getDataSource()); + DataSourceUtils.releaseConnection(con, dataSource); } } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqliteMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqliteMaxValueIncrementer.java index 2a2cc0cc3f4..f14d4c6eadb 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqliteMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqliteMaxValueIncrementer.java @@ -59,11 +59,12 @@ public class SqliteMaxValueIncrementer extends AbstractColumnMaxValueIncrementer @Override protected synchronized long getNextKey() { - Connection con = DataSourceUtils.getConnection(getDataSource()); + DataSource dataSource = obtainDataSource(); + Connection con = DataSourceUtils.getConnection(dataSource); Statement stmt = null; try { stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); + DataSourceUtils.applyTransactionTimeout(stmt, dataSource); stmt.executeUpdate("insert into " + getIncrementerName() + " values(null)"); ResultSet rs = stmt.executeQuery("select max(rowid) from " + getIncrementerName()); if (!rs.next()) { @@ -78,7 +79,7 @@ public class SqliteMaxValueIncrementer extends AbstractColumnMaxValueIncrementer } finally { JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); + DataSourceUtils.releaseConnection(con, dataSource); } } diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java index e9f5dd05aed..fa9b0c428e0 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/AbstractMultipartHttpServletRequest.java @@ -44,8 +44,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; public abstract class AbstractMultipartHttpServletRequest extends HttpServletRequestWrapper implements MultipartHttpServletRequest { - @SuppressWarnings("NullAway.Init") - private MultiValueMap multipartFiles; + private @Nullable MultiValueMap multipartFiles; /** @@ -140,7 +139,7 @@ public abstract class AbstractMultipartHttpServletRequest extends HttpServletReq if (this.multipartFiles == null) { initializeMultipart(); } - return this.multipartFiles; + return (this.multipartFiles != null ? this.multipartFiles : new LinkedMultiValueMap<>(Collections.emptyMap())); } /** diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java index 92cdb0929c9..51648ceadce 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/DefaultMultipartHttpServletRequest.java @@ -45,11 +45,9 @@ public class DefaultMultipartHttpServletRequest extends AbstractMultipartHttpSer private static final String CONTENT_TYPE = "Content-Type"; - @SuppressWarnings("NullAway.Init") - private Map multipartParameters; + private @Nullable Map multipartParameters; - @SuppressWarnings("NullAway.Init") - private Map multipartParameterContentTypes; + private @Nullable Map multipartParameterContentTypes; /** @@ -170,7 +168,7 @@ public class DefaultMultipartHttpServletRequest extends AbstractMultipartHttpSer if (this.multipartParameters == null) { initializeMultipart(); } - return this.multipartParameters; + return (this.multipartParameters != null ? this.multipartParameters : Collections.emptyMap()); } /** @@ -190,7 +188,8 @@ public class DefaultMultipartHttpServletRequest extends AbstractMultipartHttpSer if (this.multipartParameterContentTypes == null) { initializeMultipart(); } - return this.multipartParameterContentTypes; + return (this.multipartParameterContentTypes != null ? this.multipartParameterContentTypes : + Collections.emptyMap()); } } diff --git a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java index 1e05d139e8b..6cfe1ded883 100644 --- a/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java +++ b/spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java @@ -58,8 +58,7 @@ import org.springframework.web.multipart.MultipartFile; */ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest { - @SuppressWarnings("NullAway.Init") - private Set multipartParameterNames; + private @Nullable Set multipartParameterNames; /** @@ -144,7 +143,7 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe if (this.multipartParameterNames == null) { initializeMultipart(); } - if (this.multipartParameterNames.isEmpty()) { + if (CollectionUtils.isEmpty(this.multipartParameterNames)) { return super.getParameterNames(); } @@ -164,7 +163,7 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe if (this.multipartParameterNames == null) { initializeMultipart(); } - if (this.multipartParameterNames.isEmpty()) { + if (CollectionUtils.isEmpty(this.multipartParameterNames)) { return super.getParameterMap(); } diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java index 125a38816ed..127b620e202 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java @@ -86,8 +86,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa private WebSessionManager sessionManager = new DefaultWebSessionManager(); - @SuppressWarnings("NullAway.Init") - private ServerCodecConfigurer codecConfigurer; + private @Nullable ServerCodecConfigurer codecConfigurer; private LocaleContextResolver localeContextResolver = new AcceptHeaderLocaleContextResolver(); @@ -153,10 +152,12 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa * Return the configured {@link ServerCodecConfigurer}. */ public ServerCodecConfigurer getCodecConfigurer() { - if (this.codecConfigurer == null) { - setCodecConfigurer(ServerCodecConfigurer.create()); + ServerCodecConfigurer codecConfigurer = this.codecConfigurer; + if (codecConfigurer == null) { + codecConfigurer = ServerCodecConfigurer.create(); + setCodecConfigurer(codecConfigurer); } - return this.codecConfigurer; + return codecConfigurer; } /**