From f368147f9d73652d7ae9d949095a671334cdad80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Tue, 24 Dec 2024 18:27:13 +0100 Subject: [PATCH] Refine null-safety in the spring-context module Closes gh-34151 --- .../cache/jcache/interceptor/AbstractJCacheOperation.java | 4 ++-- .../jcache/interceptor/DefaultJCacheOperationSource.java | 8 ++++---- .../cache/jcache/interceptor/KeyGeneratorAdapter.java | 4 ++-- .../scheduling/quartz/LocalDataSourceJobStore.java | 2 +- .../scheduling/quartz/SchedulerAccessor.java | 4 ++-- .../scheduling/quartz/SchedulerFactoryBean.java | 2 +- .../cache/interceptor/SimpleKeyGenerator.java | 4 ++-- .../springframework/context/annotation/BeanMethod.java | 2 +- .../context/annotation/ConfigurationClass.java | 2 +- .../ConfigurationClassBeanDefinitionReader.java | 2 +- .../context/annotation/ConfigurationClassParser.java | 2 +- .../annotation/ConfigurationClassPostProcessor.java | 2 +- .../ContextAnnotationAutowireCandidateResolver.java | 1 - .../context/annotation/ProfileCondition.java | 4 ++-- .../event/AbstractApplicationEventMulticaster.java | 4 ++-- .../datetime/standard/DateTimeFormatterRegistrar.java | 2 +- .../org/springframework/jmx/export/MBeanExporter.java | 1 - .../java/org/springframework/validation/DataBinder.java | 4 +--- .../validation/DefaultMessageCodesResolver.java | 3 +-- 19 files changed, 26 insertions(+), 31 deletions(-) diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java index 8349d2513b7..56d46f49f59 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/AbstractJCacheOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -107,7 +107,7 @@ abstract class AbstractJCacheOperation implements JCacheOp } @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1113 public CacheInvocationParameter[] getAllParameters(@Nullable Object... values) { if (this.allParameterDetails.size() != values.length) { throw new IllegalStateException("Values mismatch, operation has " + 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 6b684b8e61a..850c2d0821e 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,7 +182,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } } - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation protected CacheManager getDefaultCacheManager() { if (getCacheManager() == null) { Assert.state(this.beanFactory != null, "BeanFactory required for default CacheManager resolution"); @@ -202,7 +202,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation protected CacheResolver getDefaultCacheResolver() { if (getCacheResolver() == null) { this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(getDefaultCacheManager())); @@ -211,7 +211,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc } @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation protected CacheResolver getDefaultExceptionCacheResolver() { if (getExceptionCacheResolver() == null) { this.exceptionCacheResolver = SingletonSupplier.of(new LazyCacheResolver()); diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java index 756464fcc38..60af6919741 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/KeyGeneratorAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,7 @@ class KeyGeneratorAdapter implements KeyGenerator { } @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1113 public Object generate(Object target, Method method, @Nullable Object... params) { JCacheOperation operation = this.cacheOperationSource.getCacheOperation(method, target.getClass()); if (!(operation instanceof AbstractJCacheKeyOperation)) { 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 a12b9797814..2a342916edf 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,7 +90,7 @@ public class LocalDataSourceJobStore extends JobStoreCMT { @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation 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 5947404b038..33dd9281209 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -194,7 +194,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware { /** * Register jobs and triggers (within a transaction, if possible). */ - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation 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 30b6bee93bc..44e2e4ac98c 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 @@ -644,7 +644,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe * @see #afterPropertiesSet * @see org.quartz.SchedulerFactory#getScheduler */ - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation protected Scheduler createScheduler(SchedulerFactory schedulerFactory, @Nullable String schedulerName) throws SchedulerException { diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKeyGenerator.java b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKeyGenerator.java index aa16ae05c23..f5b5437abcb 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKeyGenerator.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/SimpleKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ import org.springframework.core.KotlinDetector; public class SimpleKeyGenerator implements KeyGenerator { @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1113 public Object generate(Object target, Method method, @Nullable Object... params) { return generateKey((KotlinDetector.isSuspendingFunction(method) ? Arrays.copyOf(params, params.length - 1) : params)); 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 71f449ce7a2..3d969f14fef 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 @@ -45,7 +45,7 @@ final class BeanMethod extends ConfigurationMethod { @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Reflection public void validate(ProblemReporter problemReporter) { if (getMetadata().getAnnotationAttributes(Autowired.class.getName()) != null) { // declared as @Autowired: semantic mismatch since @Bean method arguments are autowired 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 d4d5a536c6f..7a451c6f494 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 @@ -218,7 +218,7 @@ final class ConfigurationClass { return this.importBeanDefinitionRegistrars; } - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Reflection void validate(ProblemReporter problemReporter) { Map attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName()); diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 6cf226bdefc..3b8ad11c909 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -291,7 +291,7 @@ class ConfigurationClassBeanDefinitionReader { this.registry.registerBeanDefinition(beanName, beanDefToRegister); } - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Reflection protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) { if (!this.registry.containsBeanDefinition(beanName)) { return false; 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 6d90351956b..06adae67edb 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 @@ -821,12 +821,12 @@ class ConfigurationClassParser { deferredImport.getConfigurationClass()); } - @SuppressWarnings("NullAway") void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate filter = grouping.getCandidateFilter(); grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); + Assert.state(configurationClass != null, "ConfigurationClass must not be null"); try { processImports(configurationClass, asSourceClass(configurationClass, filter), Collections.singleton(asSourceClass(entry.getImportClassName(), filter)), 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 4787f832165..a83b7c86218 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 @@ -319,7 +319,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Lazy initialization public @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { boolean hasPropertySourceDescriptors = !CollectionUtils.isEmpty(this.propertySourceDescriptors); boolean hasImportRegistry = beanFactory.containsBean(IMPORT_REGISTRY_BEAN_NAME); 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 f4d1b8bbb25..944f1d4c845 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 @@ -127,7 +127,6 @@ public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotat } @Override - @SuppressWarnings("NullAway") public Object getTarget() { Object cachedTarget = this.cachedTarget; if (cachedTarget != 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 a720639e7cb..f1c197803f3 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap; class ProfileCondition implements Condition { @Override - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Reflection 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 b46b19b7fd9..a3f3cd83e73 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -229,7 +229,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") + @SuppressWarnings("NullAway") // Dataflow analysis limitation private Collection> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class sourceType, @Nullable CachedListenerRetriever retriever) { diff --git a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.java index 8a5d09cf6be..45adcc13d27 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.java @@ -51,7 +51,7 @@ import org.springframework.format.annotation.DateTimeFormat.ISO; * @see org.springframework.format.FormatterRegistrar#registerFormatters * @see org.springframework.format.datetime.DateFormatterRegistrar */ -@SuppressWarnings("NullAway") +@SuppressWarnings("NullAway") // Well-known map keys public class DateTimeFormatterRegistrar implements FormatterRegistrar { private enum Type {DATE, TIME, DATE_TIME} diff --git a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java index 030f94263c9..97d48897ac7 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java @@ -987,7 +987,6 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * Unregister the configured {@link NotificationListener NotificationListeners} * from the {@link MBeanServer}. */ - @SuppressWarnings("NullAway") private void unregisterNotificationListeners() { if (this.server != null) { this.registeredNotificationListeners.forEach((bean, mappedObjectNames) -> { 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 7991072db02..3014de5b7b4 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -669,7 +669,6 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { } } - @SuppressWarnings("NullAway") private void assertValidators(@Nullable Validator... validators) { Object target = getTarget(); for (Validator validator : validators) { @@ -728,7 +727,6 @@ 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() : @@ -1232,7 +1230,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { * @see #getBindingErrorProcessor * @see BindingErrorProcessor#processMissingFieldError */ - @SuppressWarnings("NullAway") + @SuppressWarnings("NullAway") // Dataflow analysis limitation 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 63421ec83c0..c3f0b2205c5 100644 --- a/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java +++ b/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -243,7 +243,6 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial * {@link DefaultMessageCodesResolver#CODE_SEPARATOR}, skipping zero-length or * null elements altogether. */ - @SuppressWarnings("NullAway") public static String toDelimitedString(@Nullable String... elements) { StringJoiner rtn = new StringJoiner(CODE_SEPARATOR); for (String element : elements) {