diff --git a/gradle/spring-module.gradle b/gradle/spring-module.gradle index fdc33db87ed..d096d5b23bf 100644 --- a/gradle/spring-module.gradle +++ b/gradle/spring-module.gradle @@ -117,12 +117,11 @@ tasks.withType(JavaCompile).configureEach { options.errorprone { disableAllChecks = true option("NullAway:CustomContractAnnotations", "org.springframework.lang.Contract") - option("NullAway:AnnotatedPackages", "org.springframework.core,org.springframework.expression," + - "org.springframework.web,org.springframework.jms,org.springframework.messaging,org.springframework.jdbc," + - "org.springframework.r2dbc,org.springframework.orm,org.springframework.beans,org.springframework.aop") + option("NullAway:AnnotatedPackages", "org.springframework") option("NullAway:UnannotatedSubPackages", "org.springframework.instrument,org.springframework.context.index," + "org.springframework.asm,org.springframework.cglib,org.springframework.objenesis," + - "org.springframework.javapoet,org.springframework.aot.nativex.substitution,org.springframework.aot.nativex.feature") + "org.springframework.javapoet,org.springframework.aot.nativex.substitution,org.springframework.aot.nativex.feature," + + "org.springframework.test,org.springframework.mock") } } tasks.compileJava { diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java index 755a7374d29..dbd71ba2648 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java @@ -101,7 +101,7 @@ class CacheResultInterceptor extends AbstractKeyCacheInterceptor context) { CacheResolver exceptionCacheResolver = context.getOperation().getExceptionCacheResolver(); if (exceptionCacheResolver != null) { - return extractFrom(context.getOperation().getExceptionCacheResolver().resolveCaches(context)); + return extractFrom(exceptionCacheResolver.resolveCaches(context)); } return null; } diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java index f6f84d36046..1b93b140ba2 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java @@ -188,6 +188,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } } + @SuppressWarnings("NullAway") protected CacheManager getDefaultCacheManager() { if (getCacheManager() == null) { Assert.state(this.beanFactory != null, "BeanFactory required for default CacheManager resolution"); @@ -207,6 +208,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } @Override + @SuppressWarnings("NullAway") protected CacheResolver getDefaultCacheResolver() { if (getCacheResolver() == null) { this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(getDefaultCacheManager())); @@ -215,6 +217,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } @Override + @SuppressWarnings("NullAway") protected CacheResolver getDefaultExceptionCacheResolver() { if (getExceptionCacheResolver() == null) { this.exceptionCacheResolver = SingletonSupplier.of(new LazyCacheResolver()); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java index f6042bee934..5e68e733186 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/LocalDataSourceJobStore.java @@ -90,6 +90,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT { @Override + @SuppressWarnings("NullAway") public void initialize(ClassLoadHelper loadHelper, SchedulerSignaler signaler) throws SchedulerConfigException { // Absolutely needs thread-bound DataSource to initialize. this.dataSource = SchedulerFactoryBean.getConfigTimeDataSource(); diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java index f9d4c72ab30..e6b1c7aa543 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerAccessor.java @@ -203,6 +203,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware { /** * Register jobs and triggers (within a transaction, if possible). */ + @SuppressWarnings("NullAway") protected void registerJobsAndTriggers() throws SchedulerException { TransactionStatus transactionStatus = null; if (this.transactionManager != null) { diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index 8b69a7d50e4..937240d1a78 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -661,6 +661,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe * @see #afterPropertiesSet * @see org.quartz.SchedulerFactory#getScheduler */ + @SuppressWarnings("NullAway") protected Scheduler createScheduler(SchedulerFactory schedulerFactory, @Nullable String schedulerName) throws SchedulerException { diff --git a/spring-context/src/main/java/org/springframework/context/annotation/BeanMethod.java b/spring-context/src/main/java/org/springframework/context/annotation/BeanMethod.java index b1570ddad5a..1b41d938c28 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/BeanMethod.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/BeanMethod.java @@ -43,6 +43,7 @@ final class BeanMethod extends ConfigurationMethod { @Override + @SuppressWarnings("NullAway") public void validate(ProblemReporter problemReporter) { if ("void".equals(getMetadata().getReturnTypeName())) { // declared as void: potential misuse of @Bean, maybe meant as init method instead? diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java index 00df7a55dd7..d38a670c958 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java @@ -40,6 +40,7 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; @@ -112,14 +113,18 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser { parseBeanNameGenerator(element, scanner); } catch (Exception ex) { - parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); + String message = ex.getMessage(); + Assert.state(message != null, "Exception message must not be null"); + parserContext.getReaderContext().error(message, parserContext.extractSource(element), ex.getCause()); } try { parseScope(element, scanner); } catch (Exception ex) { - parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); + String message = ex.getMessage(); + Assert.state(message != null, "Exception message must not be null"); + parserContext.getReaderContext().error(message, parserContext.extractSource(element), ex.getCause()); } parseTypeFilters(element, scanner, parserContext); @@ -214,8 +219,10 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser { "Ignoring non-present type filter class: " + ex, parserContext.extractSource(element)); } catch (Exception ex) { + String message = ex.getMessage(); + Assert.state(message != null, "Exception message must not be null"); parserContext.getReaderContext().error( - ex.getMessage(), parserContext.extractSource(element), ex.getCause()); + message, parserContext.extractSource(element), ex.getCause()); } } } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java index dfb3c4045bb..7664cb69813 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java @@ -219,6 +219,7 @@ final class ConfigurationClass { return this.importBeanDefinitionRegistrars; } + @SuppressWarnings("NullAway") void validate(ProblemReporter problemReporter) { Map attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName()); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index e42aa2532a1..b4356d8957b 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -819,6 +819,7 @@ class ConfigurationClassParser { deferredImport.getConfigurationClass()); } + @SuppressWarnings("NullAway") void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate filter = grouping.getCandidateFilter(); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index b1a4408c6fb..336ce095626 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -325,6 +325,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo @Override @Nullable + @SuppressWarnings("NullAway") public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { boolean hasPropertySourceDescriptors = !CollectionUtils.isEmpty(this.propertySourceDescriptors); boolean hasImportRegistry = beanFactory.containsBean(IMPORT_REGISTRY_BEAN_NAME); @@ -556,6 +557,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } @Override + @Nullable public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) { // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's // postProcessProperties method attempts to autowire other configuration beans. diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java b/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java index 1718ffd4de4..dcf4aa91aeb 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java @@ -98,6 +98,7 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat return descriptor.getDependencyType(); } @Override + @SuppressWarnings("NullAway") public Object getTarget() { Set autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null); Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ProfileCondition.java b/spring-context/src/main/java/org/springframework/context/annotation/ProfileCondition.java index cc9b664921d..a720639e7cb 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ProfileCondition.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ProfileCondition.java @@ -31,6 +31,7 @@ import org.springframework.util.MultiValueMap; class ProfileCondition implements Condition { @Override + @SuppressWarnings("NullAway") public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); if (attrs != null) { diff --git a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java index 76be0c05252..14f8c44e950 100644 --- a/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java @@ -40,6 +40,7 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** @@ -229,6 +230,7 @@ public abstract class AbstractApplicationEventMulticaster * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes) * @return the pre-filtered list of application listeners for the given event and source type */ + @SuppressWarnings("NullAway") private Collection> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class sourceType, @Nullable CachedListenerRetriever retriever) { @@ -313,7 +315,7 @@ public abstract class AbstractApplicationEventMulticaster AnnotationAwareOrderComparator.sort(allListeners); if (retriever != null) { - if (filteredListenerBeans.isEmpty()) { + if (CollectionUtils.isEmpty(filteredListenerBeans)) { retriever.applicationListeners = new LinkedHashSet<>(allListeners); retriever.applicationListenerBeans = filteredListenerBeans; } diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java index b64fe8fbd5e..a717216728a 100644 --- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java @@ -460,6 +460,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe } } + @SuppressWarnings("NullAway") private String getInvocationErrorMessage(Object bean, @Nullable String message, @Nullable Object[] resolvedArgs) { StringBuilder sb = new StringBuilder(getDetailedErrorMessage(bean, message)); sb.append("Resolved arguments: \n"); diff --git a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java index 12afa030567..5f330e75452 100644 --- a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java @@ -111,7 +111,7 @@ public class EventListenerMethodProcessor @Override public void afterSingletonsInstantiated() { ConfigurableListableBeanFactory beanFactory = this.beanFactory; - Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); + Assert.state(beanFactory != null, "No ConfigurableListableBeanFactory set"); String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { diff --git a/spring-context/src/main/java/org/springframework/context/i18n/LocaleContextThreadLocalAccessor.java b/spring-context/src/main/java/org/springframework/context/i18n/LocaleContextThreadLocalAccessor.java index 4a0c09d2cab..5d31165db81 100644 --- a/spring-context/src/main/java/org/springframework/context/i18n/LocaleContextThreadLocalAccessor.java +++ b/spring-context/src/main/java/org/springframework/context/i18n/LocaleContextThreadLocalAccessor.java @@ -18,6 +18,8 @@ package org.springframework.context.i18n; import io.micrometer.context.ThreadLocalAccessor; +import org.springframework.lang.Nullable; + /** * Adapt {@link LocaleContextHolder} to the {@link ThreadLocalAccessor} contract * to assist the Micrometer Context Propagation library with {@link LocaleContext} @@ -40,6 +42,7 @@ public class LocaleContextThreadLocalAccessor implements ThreadLocalAccessor { diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java index 6f02406bb16..3398cc8803c 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java @@ -43,6 +43,7 @@ import org.springframework.core.annotation.RepeatableContainers; import org.springframework.jmx.export.metadata.InvalidMetadataException; import org.springframework.jmx.export.metadata.JmxAttributeSource; import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; /** @@ -117,7 +118,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFac pvs.removePropertyValue("defaultValue"); PropertyAccessorFactory.forBeanPropertyAccess(bean).setPropertyValues(pvs); String defaultValue = (String) map.get("defaultValue"); - if (!defaultValue.isEmpty()) { + if (StringUtils.hasLength(defaultValue)) { bean.setDefaultValue(defaultValue); } return bean; diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index c7af62b5011..8702cc52f82 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -682,7 +682,8 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { } } - private void assertValidators(Validator... validators) { + @SuppressWarnings("NullAway") + private void assertValidators(@Nullable Validator... validators) { Object target = getTarget(); for (Validator validator : validators) { if (validator != null && (target != null && !validator.supports(target.getClass()))) { @@ -741,6 +742,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * {@link #setExcludedValidators(Predicate) exclude predicate}. * @since 6.1 */ + @SuppressWarnings("NullAway") public List getValidatorsToApply() { return (this.excludedValidators != null ? this.validators.stream().filter(validator -> !this.excludedValidators.test(validator)).toList() : @@ -1168,6 +1170,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * @see #getBindingErrorProcessor * @see BindingErrorProcessor#processMissingFieldError */ + @SuppressWarnings("NullAway") protected void checkRequiredFields(MutablePropertyValues mpvs) { String[] requiredFields = getRequiredFields(); if (!ObjectUtils.isEmpty(requiredFields)) { diff --git a/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java b/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java index 15655c1cc7f..47bf72dd7b2 100644 --- a/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java +++ b/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java @@ -242,7 +242,8 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial * {@link DefaultMessageCodesResolver#CODE_SEPARATOR}, skipping zero-length or * null elements altogether. */ - public static String toDelimitedString(String... elements) { + @SuppressWarnings("NullAway") + public static String toDelimitedString(@Nullable String... elements) { StringJoiner rtn = new StringJoiner(CODE_SEPARATOR); for (String element : elements) { if (StringUtils.hasLength(element)) { diff --git a/spring-context/src/main/java/org/springframework/validation/FieldError.java b/spring-context/src/main/java/org/springframework/validation/FieldError.java index e8b03717cf1..bb57d556ff3 100644 --- a/spring-context/src/main/java/org/springframework/validation/FieldError.java +++ b/spring-context/src/main/java/org/springframework/validation/FieldError.java @@ -107,8 +107,7 @@ public class FieldError extends ObjectError { if (!super.equals(other)) { return false; } - FieldError otherError = (FieldError) other; - return (getField().equals(otherError.getField()) && + return (other instanceof FieldError otherError && getField().equals(otherError.getField()) && ObjectUtils.nullSafeEquals(getRejectedValue(), otherError.getRejectedValue()) && isBindingFailure() == otherError.isBindingFailure()); } diff --git a/spring-context/src/main/java/org/springframework/validation/method/ParameterValidationResult.java b/spring-context/src/main/java/org/springframework/validation/method/ParameterValidationResult.java index aeb0f3493bc..6f14e1de2df 100644 --- a/spring-context/src/main/java/org/springframework/validation/method/ParameterValidationResult.java +++ b/spring-context/src/main/java/org/springframework/validation/method/ParameterValidationResult.java @@ -173,8 +173,8 @@ public class ParameterValidationResult { if (!super.equals(other)) { return false; } - ParameterValidationResult otherResult = (ParameterValidationResult) other; - return (getMethodParameter().equals(otherResult.getMethodParameter()) && + return (other instanceof ParameterValidationResult otherResult && + getMethodParameter().equals(otherResult.getMethodParameter()) && ObjectUtils.nullSafeEquals(getArgument(), otherResult.getArgument()) && ObjectUtils.nullSafeEquals(getContainerIndex(), otherResult.getContainerIndex()) && ObjectUtils.nullSafeEquals(getContainerKey(), otherResult.getContainerKey())); diff --git a/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java b/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java index 1c94b9dbe5c..b6a7500ae79 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/BindingReflectionHintsRegistrar.java @@ -63,6 +63,7 @@ public class BindingReflectionHintsRegistrar { * @param hints the hints instance to use * @param types the types to register */ + @SuppressWarnings("NullAway") public void registerReflectionHints(ReflectionHints hints, @Nullable Type... types) { Set seen = new HashSet<>(); for (Type type : types) { diff --git a/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java b/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java index cf5781a60e0..54835cde378 100644 --- a/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java +++ b/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java @@ -108,7 +108,7 @@ public abstract class CoroutinesUtils { * @throws IllegalArgumentException if {@code method} is not a suspending function * @since 6.0 */ - @SuppressWarnings({"deprecation", "DataFlowIssue"}) + @SuppressWarnings({"deprecation", "DataFlowIssue", "NullAway"}) public static Publisher invokeSuspendingFunction( CoroutineContext context, Method method, @Nullable Object target, @Nullable Object... args) { diff --git a/spring-core/src/main/java/org/springframework/util/PlaceholderParser.java b/spring-core/src/main/java/org/springframework/util/PlaceholderParser.java index 4d3c3929dfd..f354029e483 100644 --- a/spring-core/src/main/java/org/springframework/util/PlaceholderParser.java +++ b/spring-core/src/main/java/org/springframework/util/PlaceholderParser.java @@ -322,6 +322,7 @@ final class PlaceholderParser { } @Override + @Nullable public String resolvePlaceholder(String placeholderName) { String value = this.resolver.resolvePlaceholder(placeholderName); if (value != null && logger.isTraceEnabled()) { @@ -358,6 +359,7 @@ final class PlaceholderParser { } public void removePlaceholder(String placeholder) { + Assert.state(this.visitedPlaceholders != null, "Visited placeholders must not be null"); this.visitedPlaceholders.remove(placeholder); } diff --git a/spring-core/src/main/java/org/springframework/util/StreamUtils.java b/spring-core/src/main/java/org/springframework/util/StreamUtils.java index c9d7035a9d2..38fa26f7646 100644 --- a/spring-core/src/main/java/org/springframework/util/StreamUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StreamUtils.java @@ -25,6 +25,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.Charset; +import org.springframework.lang.Contract; import org.springframework.lang.Nullable; /** @@ -201,6 +202,7 @@ public abstract class StreamUtils { * @throws IOException in case of I/O errors * @since 4.3 */ + @Contract("null -> fail") public static int drain(@Nullable InputStream in) throws IOException { Assert.notNull(in, "No InputStream specified"); return (int) in.transferTo(OutputStream.nullOutputStream()); diff --git a/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java b/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java index 7b43c35152c..6916fc2e406 100644 --- a/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java +++ b/spring-jms/src/main/java/org/springframework/jms/connection/JmsResourceHolder.java @@ -222,6 +222,7 @@ public class JmsResourceHolder extends ResourceHolderSupport { * for the given connection, or {@code null} if none. */ @Nullable + @SuppressWarnings("NullAway") public S getSession(Class sessionType, @Nullable Connection connection) { Deque sessions = (connection != null ? this.sessionsPerConnection.get(connection) : this.sessions); diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java index b7c6121f6fc..34501939265 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/SimpleMessageListenerContainer.java @@ -344,6 +344,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta * @see #executeListener * @see #setExposeListenerSession */ + @SuppressWarnings("NullAway") protected void processMessage(Message message, Session session) { ConnectionFactory connectionFactory = getConnectionFactory(); boolean exposeResource = (connectionFactory != null && isExposeListenerSession()); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java index e4cf46db7ba..1b6c87f8174 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/rsocket/service/RSocketServiceMethod.java @@ -92,6 +92,7 @@ final class RSocketServiceMethod { } @Nullable + @SuppressWarnings("NullAway") private static String initRoute( Method method, Class containingClass, RSocketStrategies strategies, @Nullable StringValueResolver embeddedValueResolver) { diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index 481b37abea2..e6ac691473b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -203,6 +203,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr }); } + @SuppressWarnings("NullAway") private void registerInstantiatorForReflection(ReflectionHints reflection, @Nullable Annotation annotation) { if (annotation == null) { return; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index 7d8f1c476f8..a02fd664cf9 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -409,7 +409,9 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init future.get(); } catch (ExecutionException ex) { - if (txAttr.rollbackOn(ex.getCause())) { + Throwable cause = ex.getCause(); + Assert.state(cause != null, "Cause must not be null"); + if (txAttr.rollbackOn(cause)) { status.setRollbackOnly(); } } @@ -901,7 +903,9 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init @Override public String toString() { - return getCause().toString(); + Throwable cause = getCause(); + Assert.state(cause != null, "Cause must not be null"); + return cause.toString(); } } diff --git a/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java b/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java index ec324b8353d..905e95a0d03 100644 --- a/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java +++ b/spring-web/src/main/java/org/springframework/http/InvalidMediaTypeException.java @@ -16,6 +16,7 @@ package org.springframework.http; +import org.springframework.lang.Nullable; import org.springframework.util.InvalidMimeTypeException; /** @@ -36,8 +37,8 @@ public class InvalidMediaTypeException extends IllegalArgumentException { * @param mediaType the offending media type * @param message a detail message indicating the invalid part */ - public InvalidMediaTypeException(String mediaType, String message) { - super("Invalid media type \"" + mediaType + "\": " + message); + public InvalidMediaTypeException(String mediaType, @Nullable String message) { + super(message != null ? "Invalid media type \"" + mediaType + "\": " + message : "Invalid media type \"" + mediaType); this.mediaType = mediaType; } diff --git a/spring-web/src/main/java/org/springframework/http/RequestEntity.java b/spring-web/src/main/java/org/springframework/http/RequestEntity.java index 364a1373bfa..d387735f8b7 100644 --- a/spring-web/src/main/java/org/springframework/http/RequestEntity.java +++ b/spring-web/src/main/java/org/springframework/http/RequestEntity.java @@ -205,8 +205,8 @@ public class RequestEntity extends HttpEntity { if (!super.equals(other)) { return false; } - RequestEntity otherEntity = (RequestEntity) other; - return (ObjectUtils.nullSafeEquals(this.method, otherEntity.method) && + return (other instanceof RequestEntity otherEntity && + ObjectUtils.nullSafeEquals(this.method, otherEntity.method) && ObjectUtils.nullSafeEquals(this.url, otherEntity.url)); } @@ -736,8 +736,8 @@ public class RequestEntity extends HttpEntity { if (!super.equals(other)) { return false; } - UriTemplateRequestEntity otherEntity = (UriTemplateRequestEntity) other; - return (ObjectUtils.nullSafeEquals(this.uriTemplate, otherEntity.uriTemplate) && + return (other instanceof UriTemplateRequestEntity otherEntity && + ObjectUtils.nullSafeEquals(this.uriTemplate, otherEntity.uriTemplate) && ObjectUtils.nullSafeEquals(this.uriVarsArray, otherEntity.uriVarsArray) && ObjectUtils.nullSafeEquals(this.uriVarsMap, otherEntity.uriVarsMap)); } diff --git a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java index 2d60ec47345..350e11a2aba 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java @@ -162,8 +162,7 @@ public class ResponseEntity extends HttpEntity { if (!super.equals(other)) { return false; } - ResponseEntity otherEntity = (ResponseEntity) other; - return ObjectUtils.nullSafeEquals(this.status, otherEntity.status); + return (other instanceof ResponseEntity otherEntity && ObjectUtils.nullSafeEquals(this.status, otherEntity.status)); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/client/AbstractStreamingClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/AbstractStreamingClientHttpRequest.java index fd0f4fcccf1..fa3ea1dfea4 100644 --- a/spring-web/src/main/java/org/springframework/http/client/AbstractStreamingClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/AbstractStreamingClientHttpRequest.java @@ -63,6 +63,7 @@ abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequ } @Override + @SuppressWarnings("NullAway") protected final ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { if (this.body == null && this.bodyStream != null) { this.body = outputStream -> this.bodyStream.writeTo(outputStream); diff --git a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java index 3237f32adc6..971722b75d8 100644 --- a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java @@ -90,6 +90,7 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { @Override + @SuppressWarnings("NullAway") protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException { try { HttpRequest request = buildRequest(headers, body); diff --git a/spring-web/src/main/java/org/springframework/http/client/JettyClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/JettyClientHttpRequest.java index c8462dda81d..c846684e410 100644 --- a/spring-web/src/main/java/org/springframework/http/client/JettyClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/JettyClientHttpRequest.java @@ -69,6 +69,7 @@ class JettyClientHttpRequest extends AbstractStreamingClientHttpRequest { } @Override + @SuppressWarnings("NullAway") protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException { if (!headers.isEmpty()) { this.request.headers(httpFields -> { diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java index f012b928397..61289b03e92 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java @@ -138,6 +138,7 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader lines, ResolvableType valueType, boolean shouldWrap, Map hints) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java index e0097c03674..00e35677388 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java @@ -49,6 +49,7 @@ import org.springframework.lang.Nullable; * @author Arjen Poutsma * @since 5.3 */ +@SuppressWarnings("NullAway") final class MultipartParser extends BaseSubscriber { private static final byte CR = '\r'; @@ -115,6 +116,7 @@ final class MultipartParser extends BaseSubscriber { } @Override + @SuppressWarnings("NullAway") protected void hookOnNext(DataBuffer value) { this.requestOutstanding.set(false); this.state.get().onNext(value); diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java index 6519b8c7b0d..cb7b94b8bdb 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java @@ -57,6 +57,7 @@ import org.springframework.util.FastByteArrayOutputStream; * @author Arjen Poutsma * @since 5.3 */ +@SuppressWarnings("NullAway") final class PartGenerator extends BaseSubscriber { private static final Log logger = LogFactory.getLog(PartGenerator.class); diff --git a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java index 732e2c82e57..dd6561dd04d 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java @@ -167,6 +167,7 @@ public class ResourceRegionHttpMessageConverter extends AbstractGenericHttpMessa } } + @SuppressWarnings("NullAway") private void writeResourceRegionCollection(Collection resourceRegions, HttpOutputMessage outputMessage) throws IOException { diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 81c7165b5cc..2fd9f47179f 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -329,7 +329,8 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener } // Do not log warning for serializer not found (note: different message wording on Jackson 2.9) - boolean debugLevel = (cause instanceof JsonMappingException && cause.getMessage().startsWith("Cannot find")); + boolean debugLevel = (cause instanceof JsonMappingException && cause.getMessage() != null && + cause.getMessage().startsWith("Cannot find")); if (debugLevel ? logger.isDebugEnabled() : logger.isWarnEnabled()) { String msg = "Failed to evaluate Jackson " + (type instanceof JavaType ? "de" : "") + diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java index a3753486c35..72d68e8b052 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerReadPublisher.java @@ -47,6 +47,7 @@ import org.springframework.util.Assert; * @since 5.0 * @param the type of element signaled */ +@SuppressWarnings("NullAway") public abstract class AbstractListenerReadPublisher implements Publisher { /** diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java index a7665be2870..2392f85ea92 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteFlushProcessor.java @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * @since 5.0 * @param the type of element signaled to the {@link Subscriber} */ +@SuppressWarnings("NullAway") public abstract class AbstractListenerWriteFlushProcessor implements Processor, Void> { /** diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java index 7e81b6e72b3..ef9b8976b1b 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractListenerWriteProcessor.java @@ -43,6 +43,7 @@ import org.springframework.util.StringUtils; * @since 5.0 * @param the type of element signaled to the {@link Subscriber} */ +@SuppressWarnings("NullAway") public abstract class AbstractListenerWriteProcessor implements Processor { /** diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpRequest.java index 531718eb5c0..fd8fb73524e 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpRequest.java @@ -131,6 +131,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest { return new URI(url.toString()); } + @SuppressWarnings("NullAway") private static MultiValueMap initHeaders( MultiValueMap headerValues, HttpServletRequest request) { diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java b/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java index 63ac63dd355..da41ee1450f 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/WriteResultPublisher.java @@ -36,6 +36,7 @@ import org.springframework.util.Assert; * @author Rossen Stoyanchev * @since 5.0 */ +@SuppressWarnings("NullAway") class WriteResultPublisher implements Publisher { /** diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java index 206be4e06be..1ebf85b41e2 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceMethod.java @@ -489,7 +489,9 @@ final class HttpServiceMethod { return request -> client.exchangeForEntityFlux(request, bodyType) .map(entity -> { - Object body = reactiveAdapter.fromPublisher(entity.getBody()); + Flux entityBody = entity.getBody(); + Assert.state(entityBody != null, "Entity body must not be null"); + Object body = reactiveAdapter.fromPublisher(entityBody); return new ResponseEntity<>(body, entity.getHeaders(), entity.getStatusCode()); }); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java index a9c8380bceb..3b9bdfd6a5e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java @@ -177,6 +177,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi if (this.embeddedValueResolver != null) { prefix = this.embeddedValueResolver.resolveStringValue(prefix); } + Assert.state(prefix != null, "Prefix must not be null"); info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info); break; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index a3bfda40648..f1d65922816 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -141,7 +141,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements * @throws HttpMediaTypeNotSupportedException if no suitable message converter is found */ @Nullable - @SuppressWarnings({"rawtypes", "unchecked"}) + @SuppressWarnings({"rawtypes", "unchecked", "NullAway"}) protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java index 3744ce0f8ce..9d700ef2dae 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/MessageTag.java @@ -306,6 +306,7 @@ public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware { * Resolve the specified message into a concrete message String. * The returned message String should be unescaped. */ + @SuppressWarnings("NullAway") protected String resolveMessage() throws JspException, NoSuchMessageException { MessageSource messageSource = getMessageSource();