mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Add nullability annotations to core/spring-boot-autoconfigure
See gh-46587
This commit is contained in:
@@ -90,4 +90,5 @@
|
||||
<suppress files="PemPrivateKeyParser\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
|
||||
<suppress files="Bindable\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
|
||||
<suppress files="LambdaSafe\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
|
||||
<suppress files="ConditionMessage\.java" checks="NoWhitespaceBefore" message="'...' is preceded with whitespace"/>
|
||||
</suppressions>
|
||||
|
||||
+5
-3
@@ -22,6 +22,8 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
@@ -50,7 +52,7 @@ public abstract class AbstractDependsOnBeanFactoryPostProcessor implements BeanF
|
||||
|
||||
private final Class<?> beanClass;
|
||||
|
||||
private final Class<? extends FactoryBean<?>> factoryBeanClass;
|
||||
private final @Nullable Class<? extends FactoryBean<?>> factoryBeanClass;
|
||||
|
||||
private final Function<ListableBeanFactory, Set<String>> dependsOn;
|
||||
|
||||
@@ -61,7 +63,7 @@ public abstract class AbstractDependsOnBeanFactoryPostProcessor implements BeanF
|
||||
* @param dependsOn dependency names
|
||||
*/
|
||||
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
|
||||
Class<? extends FactoryBean<?>> factoryBeanClass, String... dependsOn) {
|
||||
@Nullable Class<? extends FactoryBean<?>> factoryBeanClass, String... dependsOn) {
|
||||
this.beanClass = beanClass;
|
||||
this.factoryBeanClass = factoryBeanClass;
|
||||
this.dependsOn = (beanFactory) -> new HashSet<>(Arrays.asList(dependsOn));
|
||||
@@ -75,7 +77,7 @@ public abstract class AbstractDependsOnBeanFactoryPostProcessor implements BeanF
|
||||
* @since 2.1.7
|
||||
*/
|
||||
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
|
||||
Class<? extends FactoryBean<?>> factoryBeanClass, Class<?>... dependencyTypes) {
|
||||
@Nullable Class<? extends FactoryBean<?>> factoryBeanClass, Class<?>... dependencyTypes) {
|
||||
this.beanClass = beanClass;
|
||||
this.factoryBeanClass = factoryBeanClass;
|
||||
this.dependsOn = (beanFactory) -> Arrays.stream(dependencyTypes)
|
||||
|
||||
+6
-1
@@ -19,12 +19,15 @@ package org.springframework.boot.autoconfigure;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.boot.context.annotation.ImportCandidates;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link TypeFilter} implementation that matches registered auto-configuration classes.
|
||||
@@ -35,9 +38,10 @@ import org.springframework.core.type.filter.TypeFilter;
|
||||
*/
|
||||
public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private volatile List<String> autoConfigurations;
|
||||
private volatile @Nullable List<String> autoConfigurations;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
@@ -66,6 +70,7 @@ public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoad
|
||||
ImportCandidates importCandidates = ImportCandidates.load(AutoConfiguration.class, this.beanClassLoader);
|
||||
this.autoConfigurations = importCandidates.getCandidates();
|
||||
}
|
||||
Assert.state(this.autoConfigurations != null, "'autoConfigurations' must not be null");
|
||||
return this.autoConfigurations;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
@@ -54,6 +56,6 @@ public interface AutoConfigurationImportFilter {
|
||||
* {@code autoConfigurationClasses} parameter. Entries containing {@code false} will
|
||||
* not be imported.
|
||||
*/
|
||||
boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);
|
||||
boolean[] match(@Nullable String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);
|
||||
|
||||
}
|
||||
|
||||
+31
-12
@@ -32,6 +32,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.Aware;
|
||||
@@ -89,23 +90,27 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
|
||||
private final Class<?> autoConfigurationAnnotation;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private Environment environment;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private volatile ConfigurationClassFilter configurationClassFilter;
|
||||
private volatile @Nullable ConfigurationClassFilter configurationClassFilter;
|
||||
|
||||
private volatile AutoConfigurationReplacements autoConfigurationReplacements;
|
||||
private volatile @Nullable AutoConfigurationReplacements autoConfigurationReplacements;
|
||||
|
||||
public AutoConfigurationImportSelector() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
AutoConfigurationImportSelector(Class<?> autoConfigurationAnnotation) {
|
||||
AutoConfigurationImportSelector(@Nullable Class<?> autoConfigurationAnnotation) {
|
||||
this.autoConfigurationAnnotation = (autoConfigurationAnnotation != null) ? autoConfigurationAnnotation
|
||||
: AutoConfiguration.class;
|
||||
}
|
||||
@@ -168,7 +173,7 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
* @param metadata the annotation metadata
|
||||
* @return annotation attributes
|
||||
*/
|
||||
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
|
||||
protected @Nullable AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
|
||||
String name = getAnnotationClass().getName();
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
|
||||
Assert.state(attributes != null, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
|
||||
@@ -192,7 +197,8 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
* attributes}
|
||||
* @return a list of candidate configurations
|
||||
*/
|
||||
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
|
||||
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
|
||||
@Nullable AnnotationAttributes attributes) {
|
||||
ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,
|
||||
getBeanClassLoader());
|
||||
List<String> configurations = importCandidates.getCandidates();
|
||||
@@ -237,10 +243,12 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
* attributes}
|
||||
* @return exclusions or an empty set
|
||||
*/
|
||||
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
|
||||
protected Set<String> getExclusions(AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {
|
||||
Set<String> excluded = new LinkedHashSet<>();
|
||||
excluded.addAll(asList(attributes, "exclude"));
|
||||
excluded.addAll(asList(attributes, "excludeName"));
|
||||
if (attributes != null) {
|
||||
excluded.addAll(asList(attributes, "exclude"));
|
||||
excluded.addAll(asList(attributes, "excludeName"));
|
||||
}
|
||||
excluded.addAll(getExcludeAutoConfigurationsProperty());
|
||||
return getAutoConfigurationReplacements().replaceAll(excluded);
|
||||
}
|
||||
@@ -389,7 +397,7 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
|
||||
List<String> filter(List<String> configurations) {
|
||||
long startTime = System.nanoTime();
|
||||
String[] candidates = StringUtils.toStringArray(configurations);
|
||||
@Nullable String[] candidates = StringUtils.toStringArray(configurations);
|
||||
boolean skipped = false;
|
||||
for (AutoConfigurationImportFilter filter : this.filters) {
|
||||
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
|
||||
@@ -426,15 +434,18 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
|
||||
private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
private @Nullable AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
|
||||
private AutoConfigurationReplacements autoConfigurationReplacements;
|
||||
private @Nullable AutoConfigurationReplacements autoConfigurationReplacements;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
@@ -488,10 +499,16 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
processedConfigurations.removeAll(allExclusions);
|
||||
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
|
||||
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
|
||||
.map(this::getEntry)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Entry getEntry(String importClassName) {
|
||||
AnnotationMetadata metadata = this.entries.get(importClassName);
|
||||
Assert.state(metadata != null, "'metadata' must not be null");
|
||||
return new Entry(metadata, importClassName);
|
||||
}
|
||||
|
||||
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
|
||||
if (this.autoConfigurationMetadata == null) {
|
||||
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
|
||||
@@ -501,6 +518,8 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
|
||||
|
||||
private List<String> sortAutoConfigurations(Set<String> configurations,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
Assert.state(this.autoConfigurationReplacements != null,
|
||||
"'autoConfigurationReplacements' must not be null");
|
||||
return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata,
|
||||
this.autoConfigurationReplacements::replace)
|
||||
.getInPriorityOrder(configurations);
|
||||
|
||||
+13
-6
@@ -18,6 +18,10 @@ package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
|
||||
/**
|
||||
* Provides access to meta-data written by the auto-configure annotation processor.
|
||||
*
|
||||
@@ -40,7 +44,7 @@ public interface AutoConfigurationMetadata {
|
||||
* @param key the meta-data key
|
||||
* @return the meta-data value or {@code null}
|
||||
*/
|
||||
Integer getInteger(String className, String key);
|
||||
@Nullable Integer getInteger(String className, String key);
|
||||
|
||||
/**
|
||||
* Get an {@link Integer} value from the meta-data.
|
||||
@@ -49,7 +53,8 @@ public interface AutoConfigurationMetadata {
|
||||
* @param defaultValue the default value
|
||||
* @return the meta-data value or {@code defaultValue}
|
||||
*/
|
||||
Integer getInteger(String className, String key, Integer defaultValue);
|
||||
@Contract("_, _, !null -> !null")
|
||||
@Nullable Integer getInteger(String className, String key, @Nullable Integer defaultValue);
|
||||
|
||||
/**
|
||||
* Get a {@link Set} value from the meta-data.
|
||||
@@ -57,7 +62,7 @@ public interface AutoConfigurationMetadata {
|
||||
* @param key the meta-data key
|
||||
* @return the meta-data value or {@code null}
|
||||
*/
|
||||
Set<String> getSet(String className, String key);
|
||||
@Nullable Set<String> getSet(String className, String key);
|
||||
|
||||
/**
|
||||
* Get a {@link Set} value from the meta-data.
|
||||
@@ -66,7 +71,8 @@ public interface AutoConfigurationMetadata {
|
||||
* @param defaultValue the default value
|
||||
* @return the meta-data value or {@code defaultValue}
|
||||
*/
|
||||
Set<String> getSet(String className, String key, Set<String> defaultValue);
|
||||
@Contract("_, _, !null -> !null")
|
||||
@Nullable Set<String> getSet(String className, String key, @Nullable Set<String> defaultValue);
|
||||
|
||||
/**
|
||||
* Get an {@link String} value from the meta-data.
|
||||
@@ -74,7 +80,7 @@ public interface AutoConfigurationMetadata {
|
||||
* @param key the meta-data key
|
||||
* @return the meta-data value or {@code null}
|
||||
*/
|
||||
String get(String className, String key);
|
||||
@Nullable String get(String className, String key);
|
||||
|
||||
/**
|
||||
* Get an {@link String} value from the meta-data.
|
||||
@@ -83,6 +89,7 @@ public interface AutoConfigurationMetadata {
|
||||
* @param defaultValue the default value
|
||||
* @return the meta-data value or {@code defaultValue}
|
||||
*/
|
||||
String get(String className, String key, String defaultValue);
|
||||
@Contract("_, _, !null -> !null")
|
||||
@Nullable String get(String className, String key, @Nullable String defaultValue);
|
||||
|
||||
}
|
||||
|
||||
+9
-7
@@ -22,6 +22,8 @@ import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -42,7 +44,7 @@ final class AutoConfigurationMetadataLoader {
|
||||
return loadMetadata(classLoader, PATH);
|
||||
}
|
||||
|
||||
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
|
||||
static AutoConfigurationMetadata loadMetadata(@Nullable ClassLoader classLoader, String path) {
|
||||
try {
|
||||
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
|
||||
: ClassLoader.getSystemResources(path);
|
||||
@@ -78,34 +80,34 @@ final class AutoConfigurationMetadataLoader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInteger(String className, String key) {
|
||||
public @Nullable Integer getInteger(String className, String key) {
|
||||
return getInteger(className, key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInteger(String className, String key, Integer defaultValue) {
|
||||
public @Nullable Integer getInteger(String className, String key, @Nullable Integer defaultValue) {
|
||||
String value = get(className, key);
|
||||
return (value != null) ? Integer.valueOf(value) : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSet(String className, String key) {
|
||||
public @Nullable Set<String> getSet(String className, String key) {
|
||||
return getSet(className, key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSet(String className, String key, Set<String> defaultValue) {
|
||||
public @Nullable Set<String> getSet(String className, String key, @Nullable Set<String> defaultValue) {
|
||||
String value = get(className, key);
|
||||
return (value != null) ? StringUtils.commaDelimitedListToSet(value) : defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String className, String key) {
|
||||
public @Nullable String get(String className, String key) {
|
||||
return get(className, key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String className, String key, String defaultValue) {
|
||||
public @Nullable String get(String className, String key, @Nullable String defaultValue) {
|
||||
String value = this.properties.getProperty(className + "." + key);
|
||||
return (value != null) ? value : defaultValue;
|
||||
}
|
||||
|
||||
+6
-2
@@ -30,12 +30,14 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.context.annotation.DeterminableImports;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -105,8 +107,9 @@ public abstract class AutoConfigurationPackages {
|
||||
private static void addBasePackages(BeanDefinition beanDefinition, String[] additionalBasePackages) {
|
||||
ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
|
||||
if (constructorArgumentValues.hasIndexedArgumentValue(0)) {
|
||||
String[] existingPackages = (String[]) constructorArgumentValues.getIndexedArgumentValue(0, String[].class)
|
||||
.getValue();
|
||||
ValueHolder indexedArgumentValue = constructorArgumentValues.getIndexedArgumentValue(0, String[].class);
|
||||
Assert.state(indexedArgumentValue != null, "'indexedArgumentValue' must not be null");
|
||||
String[] existingPackages = (String[]) indexedArgumentValue.getValue();
|
||||
constructorArgumentValues.addIndexedArgumentValue(0,
|
||||
Stream.concat(Stream.of(existingPackages), Stream.of(additionalBasePackages))
|
||||
.distinct()
|
||||
@@ -145,6 +148,7 @@ public abstract class AutoConfigurationPackages {
|
||||
PackageImports(AnnotationMetadata metadata) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
List<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));
|
||||
for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
|
||||
packageNames.add(basePackageClass.getPackage().getName());
|
||||
|
||||
+4
-2
@@ -28,6 +28,8 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.annotation.ImportCandidates;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -88,7 +90,7 @@ final class AutoConfigurationReplacements {
|
||||
* @param classLoader class loader to use for loading
|
||||
* @return list of names of annotated classes
|
||||
*/
|
||||
static AutoConfigurationReplacements load(Class<?> annotation, ClassLoader classLoader) {
|
||||
static AutoConfigurationReplacements load(Class<?> annotation, @Nullable ClassLoader classLoader) {
|
||||
Assert.notNull(annotation, "'annotation' must not be null");
|
||||
ClassLoader classLoaderToUse = decideClassloader(classLoader);
|
||||
String location = String.format(LOCATION, annotation.getName());
|
||||
@@ -101,7 +103,7 @@ final class AutoConfigurationReplacements {
|
||||
return new AutoConfigurationReplacements(replacements);
|
||||
}
|
||||
|
||||
private static ClassLoader decideClassloader(ClassLoader classLoader) {
|
||||
private static ClassLoader decideClassloader(@Nullable ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
return ImportCandidates.class.getClassLoader();
|
||||
}
|
||||
|
||||
+28
-18
@@ -30,6 +30,8 @@ import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
@@ -47,12 +49,13 @@ class AutoConfigurationSorter {
|
||||
|
||||
private final MetadataReaderFactory metadataReaderFactory;
|
||||
|
||||
private final AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
private final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
|
||||
private final UnaryOperator<String> replacementMapper;
|
||||
private final @Nullable UnaryOperator<String> replacementMapper;
|
||||
|
||||
AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata, UnaryOperator<String> replacementMapper) {
|
||||
@Nullable AutoConfigurationMetadata autoConfigurationMetadata,
|
||||
@Nullable UnaryOperator<String> replacementMapper) {
|
||||
Assert.notNull(metadataReaderFactory, "'metadataReaderFactory' must not be null");
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.autoConfigurationMetadata = autoConfigurationMetadata;
|
||||
@@ -91,7 +94,7 @@ class AutoConfigurationSorter {
|
||||
}
|
||||
|
||||
private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort, Set<String> sorted,
|
||||
Set<String> processing, String current) {
|
||||
Set<String> processing, @Nullable String current) {
|
||||
if (current == null) {
|
||||
current = toSort.remove(0);
|
||||
}
|
||||
@@ -118,7 +121,7 @@ class AutoConfigurationSorter {
|
||||
private final Map<String, AutoConfigurationClass> classes = new LinkedHashMap<>();
|
||||
|
||||
AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
|
||||
@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
|
||||
addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
|
||||
}
|
||||
|
||||
@@ -127,7 +130,8 @@ class AutoConfigurationSorter {
|
||||
}
|
||||
|
||||
private void addToClasses(MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames, boolean required) {
|
||||
@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames,
|
||||
boolean required) {
|
||||
for (String className : classNames) {
|
||||
if (!this.classes.containsKey(className)) {
|
||||
AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(className,
|
||||
@@ -147,7 +151,9 @@ class AutoConfigurationSorter {
|
||||
}
|
||||
|
||||
AutoConfigurationClass get(String className) {
|
||||
return this.classes.get(className);
|
||||
AutoConfigurationClass autoConfigurationClass = this.classes.get(className);
|
||||
Assert.state(autoConfigurationClass != null, "'autoConfigurationClass' must not be null");
|
||||
return autoConfigurationClass;
|
||||
}
|
||||
|
||||
Set<String> getClassesRequestedAfter(String className) {
|
||||
@@ -168,16 +174,16 @@ class AutoConfigurationSorter {
|
||||
|
||||
private final MetadataReaderFactory metadataReaderFactory;
|
||||
|
||||
private final AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
private final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
|
||||
private volatile AnnotationMetadata annotationMetadata;
|
||||
private volatile @Nullable AnnotationMetadata annotationMetadata;
|
||||
|
||||
private volatile Set<String> before;
|
||||
private volatile @Nullable Set<String> before;
|
||||
|
||||
private volatile Set<String> after;
|
||||
private volatile @Nullable Set<String> after;
|
||||
|
||||
AutoConfigurationClass(String className, MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
@Nullable AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
this.className = className;
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.autoConfigurationMetadata = autoConfigurationMetadata;
|
||||
@@ -210,12 +216,15 @@ class AutoConfigurationSorter {
|
||||
}
|
||||
|
||||
private Set<String> getClassNames(String metadataKey, Class<? extends Annotation> annotation) {
|
||||
Set<String> annotationValue = wasProcessed()
|
||||
? this.autoConfigurationMetadata.getSet(this.className, metadataKey, Collections.emptySet())
|
||||
: getAnnotationValue(annotation);
|
||||
Set<String> annotationValue = wasProcessed() ? getSet(metadataKey) : getAnnotationValue(annotation);
|
||||
return applyReplacements(annotationValue);
|
||||
}
|
||||
|
||||
private Set<String> getSet(String metadataKey) {
|
||||
Assert.state(this.autoConfigurationMetadata != null, "'autoConfigurationMetadata' must not be null");
|
||||
return this.autoConfigurationMetadata.getSet(this.className, metadataKey, Collections.emptySet());
|
||||
}
|
||||
|
||||
private Set<String> applyReplacements(Set<String> values) {
|
||||
if (AutoConfigurationSorter.this.replacementMapper == null) {
|
||||
return values;
|
||||
@@ -229,10 +238,11 @@ class AutoConfigurationSorter {
|
||||
|
||||
private int getOrder() {
|
||||
if (wasProcessed()) {
|
||||
Assert.state(this.autoConfigurationMetadata != null, "'autoConfigurationMetadata' must not be null");
|
||||
return this.autoConfigurationMetadata.getInteger(this.className, "AutoConfigureOrder",
|
||||
AutoConfigureOrder.DEFAULT_ORDER);
|
||||
}
|
||||
Map<String, Object> attributes = getAnnotationMetadata()
|
||||
Map<String, @Nullable Object> attributes = getAnnotationMetadata()
|
||||
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
|
||||
return (attributes != null) ? (Integer) attributes.get("value") : AutoConfigureOrder.DEFAULT_ORDER;
|
||||
}
|
||||
@@ -243,8 +253,8 @@ class AutoConfigurationSorter {
|
||||
}
|
||||
|
||||
private Set<String> getAnnotationValue(Class<?> annotation) {
|
||||
Map<String, Object> attributes = getAnnotationMetadata().getAnnotationAttributes(annotation.getName(),
|
||||
true);
|
||||
Map<String, @Nullable Object> attributes = getAnnotationMetadata()
|
||||
.getAnnotationAttributes(annotation.getName(), true);
|
||||
if (attributes == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
+9
-6
@@ -28,6 +28,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.annotation.DeterminableImports;
|
||||
import org.springframework.boot.context.annotation.ImportCandidates;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
@@ -71,12 +73,13 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
|
||||
protected @Nullable AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
|
||||
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
|
||||
@Nullable AnnotationAttributes attributes) {
|
||||
List<String> candidates = new ArrayList<>();
|
||||
Map<Class<?>, List<Annotation>> annotations = getAnnotations(metadata);
|
||||
annotations.forEach(
|
||||
@@ -93,13 +96,13 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
|
||||
private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {
|
||||
String[] classes = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get("classes");
|
||||
if (classes.length > 0) {
|
||||
if (classes != null && classes.length > 0) {
|
||||
return Arrays.asList(classes);
|
||||
}
|
||||
return loadFactoryNames(source).stream().map(this::mapFactoryName).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
private String mapFactoryName(String name) {
|
||||
private @Nullable String mapFactoryName(String name) {
|
||||
if (!name.startsWith(OPTIONAL_PREFIX)) {
|
||||
return name;
|
||||
}
|
||||
@@ -117,7 +120,7 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
|
||||
protected Set<String> getExclusions(AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {
|
||||
Set<String> exclusions = new LinkedHashSet<>();
|
||||
Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), getBeanClassLoader());
|
||||
for (String annotationName : ANNOTATION_NAMES) {
|
||||
@@ -148,7 +151,7 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
|
||||
return Collections.unmodifiableMap(annotations);
|
||||
}
|
||||
|
||||
private void collectAnnotations(Class<?> source, MultiValueMap<Class<?>, Annotation> annotations,
|
||||
private void collectAnnotations(@Nullable Class<?> source, MultiValueMap<Class<?>, Annotation> annotations,
|
||||
HashSet<Class<?>> seen) {
|
||||
if (source != null && seen.add(source)) {
|
||||
for (Annotation annotation : source.getDeclaredAnnotations()) {
|
||||
|
||||
+1
@@ -191,6 +191,7 @@ class SharedMetadataReaderFactoryContextInitializer implements
|
||||
implements FactoryBean<ConcurrentReferenceCachingMetadataReaderFactory>, ResourceLoaderAware,
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ConcurrentReferenceCachingMetadataReaderFactory metadataReaderFactory;
|
||||
|
||||
@Override
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for admin-related features.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.admin;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Spring AOP.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.aop;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for application availability features.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.availability;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration base classes for Caching support.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.cache;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+4
-2
@@ -22,6 +22,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
@@ -153,8 +155,8 @@ public abstract class AbstractNestedCondition extends SpringBootCondition implem
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
|
||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(),
|
||||
true);
|
||||
MultiValueMap<String, @Nullable Object> attributes = metadata
|
||||
.getAllAnnotationAttributes(Conditional.class.getName(), true);
|
||||
Object values = (attributes != null) ? attributes.get("value") : null;
|
||||
return (List<String[]>) ((values != null) ? values : Collections.emptyList());
|
||||
}
|
||||
|
||||
+6
-4
@@ -30,6 +30,8 @@ import java.util.TreeMap;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
@@ -58,7 +60,7 @@ public final class ConditionEvaluationReport {
|
||||
|
||||
private boolean addedAncestorOutcomes;
|
||||
|
||||
private ConditionEvaluationReport parent;
|
||||
private @Nullable ConditionEvaluationReport parent;
|
||||
|
||||
private final List<String> exclusions = new ArrayList<>();
|
||||
|
||||
@@ -154,7 +156,7 @@ public final class ConditionEvaluationReport {
|
||||
* The parent report (from a parent BeanFactory if there is one).
|
||||
* @return the parent report (or null if there isn't one)
|
||||
*/
|
||||
public ConditionEvaluationReport getParent() {
|
||||
public @Nullable ConditionEvaluationReport getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
@@ -164,7 +166,7 @@ public final class ConditionEvaluationReport {
|
||||
* @param beanFactory the bean factory (may be {@code null})
|
||||
* @return the {@link ConditionEvaluationReport} or {@code null}
|
||||
*/
|
||||
public static ConditionEvaluationReport find(BeanFactory beanFactory) {
|
||||
public static @Nullable ConditionEvaluationReport find(BeanFactory beanFactory) {
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
return ConditionEvaluationReport.get((ConfigurableListableBeanFactory) beanFactory);
|
||||
}
|
||||
@@ -191,7 +193,7 @@ public final class ConditionEvaluationReport {
|
||||
}
|
||||
}
|
||||
|
||||
private static void locateParent(BeanFactory beanFactory, ConditionEvaluationReport report) {
|
||||
private static void locateParent(@Nullable BeanFactory beanFactory, ConditionEvaluationReport report) {
|
||||
if (beanFactory != null && report.parent == null && beanFactory.containsBean(BEAN_NAME)) {
|
||||
report.parent = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
|
||||
}
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -32,7 +34,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurationImportListener;
|
||||
class ConditionEvaluationReportAutoConfigurationImportListener
|
||||
implements AutoConfigurationImportListener, BeanFactoryAware {
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
private @Nullable ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
|
||||
|
||||
+19
-14
@@ -23,6 +23,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -38,13 +40,13 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public final class ConditionMessage {
|
||||
|
||||
private final String message;
|
||||
private final @Nullable String message;
|
||||
|
||||
private ConditionMessage() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private ConditionMessage(String message) {
|
||||
private ConditionMessage(@Nullable String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ public final class ConditionMessage {
|
||||
* @param message the message to append
|
||||
* @return a new {@link ConditionMessage} instance
|
||||
*/
|
||||
public ConditionMessage append(String message) {
|
||||
public ConditionMessage append(@Nullable String message) {
|
||||
if (!StringUtils.hasLength(message)) {
|
||||
return this;
|
||||
}
|
||||
@@ -158,7 +160,7 @@ public final class ConditionMessage {
|
||||
* @param messages the source messages (may be {@code null})
|
||||
* @return a new {@link ConditionMessage} instance
|
||||
*/
|
||||
public static ConditionMessage of(Collection<? extends ConditionMessage> messages) {
|
||||
public static ConditionMessage of(@Nullable Collection<? extends ConditionMessage> messages) {
|
||||
ConditionMessage result = new ConditionMessage();
|
||||
if (messages != null) {
|
||||
for (ConditionMessage message : messages) {
|
||||
@@ -296,7 +298,7 @@ public final class ConditionMessage {
|
||||
* @param reason the reason for the message
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage because(String reason) {
|
||||
public ConditionMessage because(@Nullable String reason) {
|
||||
if (StringUtils.hasLength(reason)) {
|
||||
return new ConditionMessage(ConditionMessage.this,
|
||||
StringUtils.hasLength(this.condition) ? this.condition + " " + reason : reason);
|
||||
@@ -343,7 +345,7 @@ public final class ConditionMessage {
|
||||
* @param items the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Object... items) {
|
||||
public ConditionMessage items(Object @Nullable ... items) {
|
||||
return items(Style.NORMAL, items);
|
||||
}
|
||||
|
||||
@@ -355,7 +357,7 @@ public final class ConditionMessage {
|
||||
* @param items the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Style style, Object... items) {
|
||||
public ConditionMessage items(Style style, Object @Nullable ... items) {
|
||||
return items(style, (items != null) ? Arrays.asList(items) : null);
|
||||
}
|
||||
|
||||
@@ -366,7 +368,7 @@ public final class ConditionMessage {
|
||||
* @param items the source of the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Collection<?> items) {
|
||||
public ConditionMessage items(@Nullable Collection<?> items) {
|
||||
return items(Style.NORMAL, items);
|
||||
}
|
||||
|
||||
@@ -378,7 +380,7 @@ public final class ConditionMessage {
|
||||
* @param items the source of the items (may be {@code null})
|
||||
* @return a built {@link ConditionMessage}
|
||||
*/
|
||||
public ConditionMessage items(Style style, Collection<?> items) {
|
||||
public ConditionMessage items(Style style, @Nullable Collection<?> items) {
|
||||
Assert.notNull(style, "'style' must not be null");
|
||||
StringBuilder message = new StringBuilder(this.reason);
|
||||
items = style.applyTo(items);
|
||||
@@ -408,7 +410,7 @@ public final class ConditionMessage {
|
||||
NORMAL {
|
||||
|
||||
@Override
|
||||
protected Object applyToItem(Object item) {
|
||||
protected @Nullable Object applyToItem(@Nullable Object item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -420,24 +422,27 @@ public final class ConditionMessage {
|
||||
QUOTE {
|
||||
|
||||
@Override
|
||||
protected String applyToItem(Object item) {
|
||||
protected @Nullable String applyToItem(@Nullable Object item) {
|
||||
return (item != null) ? "'" + item + "'" : null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public Collection<?> applyTo(Collection<?> items) {
|
||||
public @Nullable Collection<?> applyTo(@Nullable Collection<?> items) {
|
||||
if (items == null) {
|
||||
return null;
|
||||
}
|
||||
List<Object> result = new ArrayList<>(items.size());
|
||||
for (Object item : items) {
|
||||
result.add(applyToItem(item));
|
||||
Object applied = applyToItem(item);
|
||||
if (applied != null) {
|
||||
result.add(applied);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract Object applyToItem(Object item);
|
||||
protected abstract @Nullable Object applyToItem(@Nullable Object item);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -111,13 +113,13 @@ public class ConditionOutcome {
|
||||
* Return an outcome message or {@code null}.
|
||||
* @return the message or {@code null}
|
||||
*/
|
||||
public String getMessage() {
|
||||
public @Nullable String getMessage() {
|
||||
return this.message.isEmpty() ? null : this.message.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an outcome message or {@code null}.
|
||||
* @return the message or {@code null}
|
||||
* Return an outcome message.
|
||||
* @return the message
|
||||
*/
|
||||
public ConditionMessage getConditionMessage() {
|
||||
return this.message;
|
||||
|
||||
+21
-12
@@ -21,12 +21,15 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -39,28 +42,33 @@ import org.springframework.util.CollectionUtils;
|
||||
abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
@Override
|
||||
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
public boolean[] match(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
|
||||
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
|
||||
@Nullable ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
|
||||
boolean[] match = new boolean[outcomes.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
|
||||
if (!match[i] && outcomes[i] != null) {
|
||||
logOutcome(autoConfigurationClasses[i], outcomes[i]);
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
Assert.state(autoConfigurationClass != null, "'autoConfigurationClass' must not be null");
|
||||
logOutcome(autoConfigurationClass, outcomes[i]);
|
||||
if (report != null) {
|
||||
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
|
||||
report.recordConditionEvaluation(autoConfigurationClass, this, outcomes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
protected abstract @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata);
|
||||
|
||||
@Override
|
||||
@@ -81,8 +89,8 @@ abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
|
||||
ClassLoader classLoader) {
|
||||
protected final List<String> filter(@Nullable Collection<String> classNames, ClassNameFilter classNameFilter,
|
||||
@Nullable ClassLoader classLoader) {
|
||||
if (CollectionUtils.isEmpty(classNames)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -103,7 +111,8 @@ abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
* @return a resolved class
|
||||
* @throws ClassNotFoundException if the class cannot be found
|
||||
*/
|
||||
protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
protected static Class<?> resolve(String className, @Nullable ClassLoader classLoader)
|
||||
throws ClassNotFoundException {
|
||||
if (classLoader != null) {
|
||||
return Class.forName(className, false, classLoader);
|
||||
}
|
||||
@@ -115,7 +124,7 @@ abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
PRESENT {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
public boolean matches(String className, @Nullable ClassLoader classLoader) {
|
||||
return isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
@@ -124,15 +133,15 @@ abstract class FilteringSpringBootCondition extends SpringBootCondition
|
||||
MISSING {
|
||||
|
||||
@Override
|
||||
public boolean matches(String className, ClassLoader classLoader) {
|
||||
public boolean matches(String className, @Nullable ClassLoader classLoader) {
|
||||
return !isPresent(className, classLoader);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
abstract boolean matches(String className, ClassLoader classLoader);
|
||||
abstract boolean matches(String className, @Nullable ClassLoader classLoader);
|
||||
|
||||
private static boolean isPresent(String className, ClassLoader classLoader) {
|
||||
private static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
|
||||
+40
-26
@@ -34,6 +34,8 @@ import java.util.Set;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
@@ -60,6 +62,7 @@ import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -90,9 +93,9 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
protected final @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
if (autoConfigurationClass != null) {
|
||||
@@ -108,7 +111,8 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
|
||||
private @Nullable ConditionOutcome getOutcome(@Nullable Set<String> requiredBeanTypes,
|
||||
Class<? extends Annotation> annotation) {
|
||||
List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
|
||||
if (!missing.isEmpty()) {
|
||||
ConditionMessage message = ConditionMessage.forCondition(annotation)
|
||||
@@ -171,7 +175,9 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return ConditionOutcome
|
||||
.match(spec.message(matchMessage).found("a single bean").items(Style.QUOTE, allBeans));
|
||||
}
|
||||
Map<String, BeanDefinition> beanDefinitions = getBeanDefinitions(spec.context.getBeanFactory(), allBeans,
|
||||
ConfigurableListableBeanFactory beanFactory = spec.context.getBeanFactory();
|
||||
Assert.state(beanFactory != null, "'beanFactory' must not be null");
|
||||
Map<String, BeanDefinition> beanDefinitions = getBeanDefinitions(beanFactory, allBeans,
|
||||
spec.getStrategy() == SearchStrategy.ALL);
|
||||
List<String> primaryBeans = getPrimaryBeans(beanDefinitions);
|
||||
if (primaryBeans.size() == 1) {
|
||||
@@ -249,6 +255,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
|
||||
private ConfigurableListableBeanFactory getSearchBeanFactory(Spec<?> spec) {
|
||||
ConfigurableListableBeanFactory beanFactory = spec.getContext().getBeanFactory();
|
||||
Assert.state(beanFactory != null, "'beanFactory' must not be null'");
|
||||
if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
|
||||
BeanFactory parent = beanFactory.getParentBeanFactory();
|
||||
Assert.state(parent instanceof ConfigurableListableBeanFactory,
|
||||
@@ -269,8 +276,8 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return matchedNames;
|
||||
}
|
||||
|
||||
private boolean isCandidate(ConfigurableListableBeanFactory beanFactory, String name, BeanDefinition definition,
|
||||
Set<String> ignoredBeans) {
|
||||
private boolean isCandidate(ConfigurableListableBeanFactory beanFactory, String name,
|
||||
@Nullable BeanDefinition definition, Set<String> ignoredBeans) {
|
||||
return (!ignoredBeans.contains(name)) && (definition == null
|
||||
|| isAutowireCandidate(beanFactory, name, definition) && isDefaultCandidate(definition));
|
||||
}
|
||||
@@ -316,12 +323,14 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return (result != null) ? result : Collections.emptyMap();
|
||||
}
|
||||
|
||||
private Map<String, BeanDefinition> collectBeanDefinitionsForType(ListableBeanFactory beanFactory,
|
||||
private @Nullable Map<String, BeanDefinition> collectBeanDefinitionsForType(ListableBeanFactory beanFactory,
|
||||
boolean considerHierarchy, ResolvableType type, Set<ResolvableType> parameterizedContainers,
|
||||
Map<String, BeanDefinition> result) {
|
||||
@Nullable Map<String, BeanDefinition> result) {
|
||||
result = putAll(result, beanFactory.getBeanNamesForType(type, true, false), beanFactory);
|
||||
for (ResolvableType parameterizedContainer : parameterizedContainers) {
|
||||
ResolvableType generic = ResolvableType.forClassWithGenerics(parameterizedContainer.resolve(), type);
|
||||
Class<?> resolved = parameterizedContainer.resolve();
|
||||
Assert.state(resolved != null, "'resolved' must not be null");
|
||||
ResolvableType generic = ResolvableType.forClassWithGenerics(resolved, type);
|
||||
result = putAll(result, beanFactory.getBeanNamesForType(generic, true, false), beanFactory);
|
||||
}
|
||||
if (considerHierarchy && beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory) {
|
||||
@@ -334,7 +343,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, BeanDefinition> getBeanDefinitionsForAnnotation(ClassLoader classLoader,
|
||||
private Map<String, BeanDefinition> getBeanDefinitionsForAnnotation(@Nullable ClassLoader classLoader,
|
||||
ConfigurableListableBeanFactory beanFactory, String type, boolean considerHierarchy) throws LinkageError {
|
||||
Map<String, BeanDefinition> result = null;
|
||||
try {
|
||||
@@ -348,13 +357,14 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<? extends Annotation> resolveAnnotationType(ClassLoader classLoader, String type)
|
||||
private Class<? extends Annotation> resolveAnnotationType(@Nullable ClassLoader classLoader, String type)
|
||||
throws ClassNotFoundException {
|
||||
return (Class<? extends Annotation>) resolve(type, classLoader);
|
||||
}
|
||||
|
||||
private Map<String, BeanDefinition> collectBeanDefinitionsForAnnotation(ListableBeanFactory beanFactory,
|
||||
Class<? extends Annotation> annotationType, boolean considerHierarchy, Map<String, BeanDefinition> result) {
|
||||
private @Nullable Map<String, BeanDefinition> collectBeanDefinitionsForAnnotation(ListableBeanFactory beanFactory,
|
||||
Class<? extends Annotation> annotationType, boolean considerHierarchy,
|
||||
@Nullable Map<String, BeanDefinition> result) {
|
||||
result = putAll(result, getBeanNamesForAnnotation(beanFactory, annotationType), beanFactory);
|
||||
if (considerHierarchy) {
|
||||
BeanFactory parent = ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory();
|
||||
@@ -477,7 +487,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return matches;
|
||||
}
|
||||
|
||||
private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName,
|
||||
private @Nullable BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName,
|
||||
boolean considerHierarchy) {
|
||||
if (beanFactory.containsBeanDefinition(beanName)) {
|
||||
return beanFactory.getBeanDefinition(beanName);
|
||||
@@ -489,7 +499,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Set<String> addAll(Set<String> result, Collection<String> additional) {
|
||||
private static @Nullable Set<String> addAll(@Nullable Set<String> result, @Nullable Collection<String> additional) {
|
||||
if (CollectionUtils.isEmpty(additional)) {
|
||||
return result;
|
||||
}
|
||||
@@ -498,8 +508,8 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Map<String, BeanDefinition> putAll(Map<String, BeanDefinition> result, String[] beanNames,
|
||||
ListableBeanFactory beanFactory) {
|
||||
private static @Nullable Map<String, BeanDefinition> putAll(@Nullable Map<String, BeanDefinition> result,
|
||||
String[] beanNames, ListableBeanFactory beanFactory) {
|
||||
if (ObjectUtils.isEmpty(beanNames)) {
|
||||
return result;
|
||||
}
|
||||
@@ -517,7 +527,8 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {
|
||||
private static @Nullable BeanDefinition getBeanDefinition(String beanName,
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
try {
|
||||
return beanFactory.getBeanDefinition(beanName);
|
||||
}
|
||||
@@ -548,7 +559,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
|
||||
private final Set<ResolvableType> parameterizedContainers;
|
||||
|
||||
private final SearchStrategy strategy;
|
||||
private final @Nullable SearchStrategy strategy;
|
||||
|
||||
Spec(ConditionContext context, AnnotatedTypeMetadata metadata, MergedAnnotations annotations,
|
||||
Class<A> annotationType) {
|
||||
@@ -621,7 +632,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return resolved;
|
||||
}
|
||||
|
||||
protected void validate(BeanTypeDeductionException ex) {
|
||||
protected void validate(@Nullable BeanTypeDeductionException ex) {
|
||||
if (!hasAtLeastOneElement(getTypes(), getNames(), getAnnotations())) {
|
||||
String message = getAnnotationName() + " did not specify a bean using type, name or annotation";
|
||||
if (ex == null) {
|
||||
@@ -671,13 +682,13 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
return returnType;
|
||||
}
|
||||
|
||||
private boolean isParameterizedContainer(Class<?> type) {
|
||||
private boolean isParameterizedContainer(@Nullable Class<?> type) {
|
||||
return (type != null) && this.parameterizedContainers.stream()
|
||||
.map(ResolvableType::resolve)
|
||||
.anyMatch((container) -> container != null && container.isAssignableFrom(type));
|
||||
}
|
||||
|
||||
private ResolvableType getMethodReturnType(MethodMetadata metadata, ClassLoader classLoader)
|
||||
private ResolvableType getMethodReturnType(MethodMetadata metadata, @Nullable ClassLoader classLoader)
|
||||
throws ClassNotFoundException, LinkageError {
|
||||
Class<?> declaringClass = resolve(metadata.getDeclaringClassName(), classLoader);
|
||||
Method beanMethod = findBeanMethod(declaringClass, metadata.getMethodName());
|
||||
@@ -698,7 +709,8 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
throw new IllegalStateException("Unable to find bean method " + methodName);
|
||||
}
|
||||
|
||||
private boolean isBeanMethod(Method method) {
|
||||
@Contract("null -> false")
|
||||
private boolean isBeanMethod(@Nullable Method method) {
|
||||
return method != null && MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
|
||||
.isPresent(Bean.class);
|
||||
}
|
||||
@@ -761,8 +773,10 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
string.append(StringUtils.collectionToCommaDelimitedString(this.ignoredTypes));
|
||||
string.append("; ");
|
||||
}
|
||||
string.append("SearchStrategy: ");
|
||||
string.append(this.strategy.toString().toLowerCase(Locale.ENGLISH));
|
||||
if (this.strategy != null) {
|
||||
string.append("SearchStrategy: ");
|
||||
string.append(this.strategy.toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
string.append(")");
|
||||
return string.toString();
|
||||
}
|
||||
@@ -789,7 +803,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validate(BeanTypeDeductionException ex) {
|
||||
protected void validate(@Nullable BeanTypeDeductionException ex) {
|
||||
Assert.isTrue(getTypes().size() == 1,
|
||||
() -> getAnnotationName() + " annotations must specify only one type (got "
|
||||
+ StringUtils.collectionToCommaDelimitedString(getTypes()) + ")");
|
||||
|
||||
+25
-22
@@ -20,6 +20,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
@@ -44,7 +46,7 @@ import org.springframework.util.StringUtils;
|
||||
class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
@Override
|
||||
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
protected final @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
// Split the work and perform half in a background thread if more than one
|
||||
// processor is available. Using a single additional thread seems to offer the
|
||||
@@ -59,22 +61,22 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
}
|
||||
}
|
||||
|
||||
private ConditionOutcome[] resolveOutcomesThreaded(String[] autoConfigurationClasses,
|
||||
private @Nullable ConditionOutcome[] resolveOutcomesThreaded(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
int split = autoConfigurationClasses.length / 2;
|
||||
OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,
|
||||
autoConfigurationMetadata);
|
||||
OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,
|
||||
autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
|
||||
ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
|
||||
ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
@Nullable ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
|
||||
@Nullable ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
|
||||
@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
|
||||
System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
|
||||
private OutcomesResolver createOutcomesResolver(@Nullable String[] autoConfigurationClasses, int start, int end,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, start, end,
|
||||
autoConfigurationMetadata, getBeanClassLoader());
|
||||
@@ -112,8 +114,9 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
return ConditionOutcome.match(matchMessage);
|
||||
}
|
||||
|
||||
private List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {
|
||||
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(annotationType.getName(), true);
|
||||
private @Nullable List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {
|
||||
MultiValueMap<String, @Nullable Object> attributes = metadata
|
||||
.getAllAnnotationAttributes(annotationType.getName(), true);
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -123,7 +126,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private void addAll(List<String> list, List<Object> itemsToAdd) {
|
||||
private void addAll(List<String> list, @Nullable List<@Nullable Object> itemsToAdd) {
|
||||
if (itemsToAdd != null) {
|
||||
for (Object item : itemsToAdd) {
|
||||
Collections.addAll(list, (String[]) item);
|
||||
@@ -133,7 +136,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
private interface OutcomesResolver {
|
||||
|
||||
ConditionOutcome[] resolveOutcomes();
|
||||
@Nullable ConditionOutcome[] resolveOutcomes();
|
||||
|
||||
}
|
||||
|
||||
@@ -141,9 +144,9 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
private final Thread thread;
|
||||
|
||||
private volatile ConditionOutcome[] outcomes;
|
||||
private volatile @Nullable ConditionOutcome @Nullable [] outcomes;
|
||||
|
||||
private volatile Throwable failure;
|
||||
private volatile @Nullable Throwable failure;
|
||||
|
||||
private ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) {
|
||||
this.thread = new Thread(() -> {
|
||||
@@ -158,7 +161,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome[] resolveOutcomes() {
|
||||
public @Nullable ConditionOutcome[] resolveOutcomes() {
|
||||
try {
|
||||
this.thread.join();
|
||||
}
|
||||
@@ -169,7 +172,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
if (failure != null) {
|
||||
ReflectionUtils.rethrowRuntimeException(failure);
|
||||
}
|
||||
ConditionOutcome[] outcomes = this.outcomes;
|
||||
@Nullable ConditionOutcome[] outcomes = this.outcomes;
|
||||
return (outcomes != null) ? outcomes : new ConditionOutcome[0];
|
||||
}
|
||||
|
||||
@@ -177,7 +180,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
private static final class StandardOutcomesResolver implements OutcomesResolver {
|
||||
|
||||
private final String[] autoConfigurationClasses;
|
||||
private final @Nullable String[] autoConfigurationClasses;
|
||||
|
||||
private final int start;
|
||||
|
||||
@@ -187,7 +190,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
|
||||
private final ClassLoader beanClassLoader;
|
||||
|
||||
private StandardOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
|
||||
private StandardOutcomesResolver(@Nullable String[] autoConfigurationClasses, int start, int end,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata, ClassLoader beanClassLoader) {
|
||||
this.autoConfigurationClasses = autoConfigurationClasses;
|
||||
this.start = start;
|
||||
@@ -197,13 +200,13 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome[] resolveOutcomes() {
|
||||
public @Nullable ConditionOutcome[] resolveOutcomes() {
|
||||
return getOutcomes(this.autoConfigurationClasses, this.start, this.end, this.autoConfigurationMetadata);
|
||||
}
|
||||
|
||||
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
|
||||
private @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses, int start,
|
||||
int end, AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
|
||||
for (int i = start; i < end; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
if (autoConfigurationClass != null) {
|
||||
@@ -216,7 +219,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(String candidates) {
|
||||
private @Nullable ConditionOutcome getOutcome(String candidates) {
|
||||
try {
|
||||
if (!candidates.contains(",")) {
|
||||
return getOutcome(candidates, this.beanClassLoader);
|
||||
@@ -234,7 +237,7 @@ class OnClassCondition extends FilteringSpringBootCondition {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
|
||||
private @Nullable ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
|
||||
if (ClassNameFilter.MISSING.matches(className, classLoader)) {
|
||||
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
|
||||
.didNotFind("required class")
|
||||
|
||||
+7
-1
@@ -18,11 +18,14 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for a required {@link CloudPlatform}.
|
||||
@@ -34,8 +37,11 @@ class OnCloudPlatformCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnCloudPlatform.class.getName());
|
||||
Map<String, @Nullable Object> attributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnCloudPlatform.class.getName());
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
CloudPlatform cloudPlatform = (CloudPlatform) attributes.get("value");
|
||||
Assert.state(cloudPlatform != null, "'cloudPlatform' must not be null");
|
||||
return getMatchOutcome(context.getEnvironment(), cloudPlatform);
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
@@ -24,6 +28,7 @@ import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Condition that evaluates a SpEL expression.
|
||||
@@ -37,8 +42,11 @@ class OnExpressionCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
String expression = (String) metadata.getAnnotationAttributes(ConditionalOnExpression.class.getName())
|
||||
.get("value");
|
||||
Map<String, @Nullable Object> attributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnExpression.class.getName());
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
String expression = (String) attributes.get("value");
|
||||
Assert.state(expression != null, "'expression' must not be null");
|
||||
expression = wrapIfNecessary(expression);
|
||||
ConditionMessage.Builder messageBuilder = ConditionMessage.forCondition(ConditionalOnExpression.class,
|
||||
"(" + expression + ")");
|
||||
|
||||
+7
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnJava.Range;
|
||||
import org.springframework.boot.system.JavaVersion;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
@@ -25,6 +27,7 @@ import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for a required version of Java.
|
||||
@@ -40,9 +43,12 @@ class OnJavaCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnJava.class.getName());
|
||||
Map<String, @Nullable Object> attributes = metadata.getAnnotationAttributes(ConditionalOnJava.class.getName());
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
Range range = (Range) attributes.get("range");
|
||||
Assert.state(range != null, "'range' must not be null");
|
||||
JavaVersion version = (JavaVersion) attributes.get("value");
|
||||
Assert.state(version != null, "'version' must not be null");
|
||||
return getMatchOutcome(range, JVM_VERSION, version);
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -26,6 +28,7 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.jndi.JndiLocatorDelegate;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -39,9 +42,10 @@ class OnJndiCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap(metadata.getAnnotationAttributes(ConditionalOnJndi.class.getName()));
|
||||
String[] locations = annotationAttributes.getStringArray("value");
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
String[] locations = attributes.getStringArray("value");
|
||||
try {
|
||||
return getMatchOutcome(locations);
|
||||
}
|
||||
@@ -88,7 +92,7 @@ class OnJndiCondition extends SpringBootCondition {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public String lookupFirstLocation() {
|
||||
public @Nullable String lookupFirstLocation() {
|
||||
for (String location : this.locations) {
|
||||
try {
|
||||
lookup(location);
|
||||
|
||||
+12
-2
@@ -22,6 +22,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
@@ -129,10 +131,16 @@ class OnPropertyCondition extends SpringBootCondition {
|
||||
this.annotationType = annotationType;
|
||||
this.prefix = (!annotationAttributes.containsKey("prefix")) ? "" : getPrefix(annotationAttributes);
|
||||
this.names = getNames(annotationAttributes);
|
||||
this.havingValue = annotationAttributes.get("havingValue").toString();
|
||||
this.havingValue = getHavingValue(annotationAttributes);
|
||||
this.matchIfMissing = annotationAttributes.getBoolean("matchIfMissing");
|
||||
}
|
||||
|
||||
private static String getHavingValue(AnnotationAttributes annotationAttributes) {
|
||||
Object havingValue = annotationAttributes.get("havingValue");
|
||||
Assert.state(havingValue != null, "'havingValue' must not be null");
|
||||
return havingValue.toString();
|
||||
}
|
||||
|
||||
private String getPrefix(AnnotationAttributes annotationAttributes) {
|
||||
String prefix = annotationAttributes.getString("prefix").trim();
|
||||
if (StringUtils.hasText(prefix) && !prefix.endsWith(".")) {
|
||||
@@ -144,6 +152,8 @@ class OnPropertyCondition extends SpringBootCondition {
|
||||
private String[] getNames(AnnotationAttributes annotationAttributes) {
|
||||
String[] value = (String[]) annotationAttributes.get("value");
|
||||
String[] name = (String[]) annotationAttributes.get("name");
|
||||
Assert.state(value != null, "'value' must not be null");
|
||||
Assert.state(name != null, "'name' must not be null");
|
||||
Assert.state(value.length > 0 || name.length > 0,
|
||||
() -> "The name or value attribute of @%s must be specified"
|
||||
.formatted(ClassUtils.getShortName(this.annotationType)));
|
||||
@@ -169,7 +179,7 @@ class OnPropertyCondition extends SpringBootCondition {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMatch(String value, String requiredValue) {
|
||||
private boolean isMatch(@Nullable String value, String requiredValue) {
|
||||
if (StringUtils.hasLength(requiredValue)) {
|
||||
return requiredValue.equalsIgnoreCase(value);
|
||||
}
|
||||
|
||||
+14
-6
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
@@ -40,11 +42,14 @@ class OnResourceCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
MultiValueMap<String, Object> attributes = metadata
|
||||
MultiValueMap<String, @Nullable Object> attributes = metadata
|
||||
.getAllAnnotationAttributes(ConditionalOnResource.class.getName(), true);
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
ResourceLoader loader = context.getResourceLoader();
|
||||
List<String> locations = new ArrayList<>();
|
||||
collectValues(locations, attributes.get("resources"));
|
||||
List<@Nullable Object> resources = attributes.get("resources");
|
||||
Assert.state(resources != null, "'resources' must not be null");
|
||||
collectValues(locations, resources);
|
||||
Assert.state(!locations.isEmpty(),
|
||||
"@ConditionalOnResource annotations must specify at least one resource location");
|
||||
List<String> missing = new ArrayList<>();
|
||||
@@ -64,10 +69,13 @@ class OnResourceCondition extends SpringBootCondition {
|
||||
.items(locations));
|
||||
}
|
||||
|
||||
private void collectValues(List<String> names, List<Object> values) {
|
||||
for (Object value : values) {
|
||||
for (Object item : (Object[]) value) {
|
||||
names.add((String) item);
|
||||
private void collectValues(List<String> names, List<@Nullable Object> resources) {
|
||||
for (Object resource : resources) {
|
||||
Object[] items = (Object[]) resource;
|
||||
if (items != null) {
|
||||
for (Object item : items) {
|
||||
names.add((String) item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -18,11 +18,14 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.thread.Threading;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for a required {@link Threading}.
|
||||
@@ -34,8 +37,11 @@ class OnThreadingCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnThreading.class.getName());
|
||||
Map<String, @Nullable Object> attributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnThreading.class.getName());
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
Threading threading = (Threading) attributes.get("value");
|
||||
Assert.state(threading != null, "'threading' must not be null");
|
||||
return getMatchOutcome(context.getEnvironment(), threading);
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.web.context.reactive.ConfigurableReactiveWebEnvironment;
|
||||
@@ -27,6 +29,7 @@ import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.context.ConfigurableWebEnvironment;
|
||||
@@ -49,9 +52,9 @@ class OnWebApplicationCondition extends FilteringSpringBootCondition {
|
||||
private static final String REACTIVE_WEB_APPLICATION_CLASS = "org.springframework.web.reactive.HandlerResult";
|
||||
|
||||
@Override
|
||||
protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
|
||||
protected @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
|
||||
for (int i = 0; i < outcomes.length; i++) {
|
||||
String autoConfigurationClass = autoConfigurationClasses[i];
|
||||
if (autoConfigurationClass != null) {
|
||||
@@ -62,7 +65,7 @@ class OnWebApplicationCondition extends FilteringSpringBootCondition {
|
||||
return outcomes;
|
||||
}
|
||||
|
||||
private ConditionOutcome getOutcome(String type) {
|
||||
private @Nullable ConditionOutcome getOutcome(@Nullable String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -157,9 +160,12 @@ class OnWebApplicationCondition extends FilteringSpringBootCondition {
|
||||
}
|
||||
|
||||
private Type deduceType(AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnWebApplication.class.getName());
|
||||
Map<String, @Nullable Object> attributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnWebApplication.class.getName());
|
||||
if (attributes != null) {
|
||||
return (Type) attributes.get("type");
|
||||
Object type = attributes.get("type");
|
||||
Assert.state(type != null, "'type' must not be null");
|
||||
return (Type) type;
|
||||
}
|
||||
return Type.ANY;
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* {@code @Condition} annotations and supporting classes.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+6
-4
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.container;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.AttributeAccessor;
|
||||
|
||||
@@ -29,7 +31,7 @@ import org.springframework.core.AttributeAccessor;
|
||||
* @author Phillip Webb
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public record ContainerImageMetadata(String imageName) {
|
||||
public record ContainerImageMetadata(@Nullable String imageName) {
|
||||
|
||||
static final String NAME = ContainerImageMetadata.class.getName();
|
||||
|
||||
@@ -37,7 +39,7 @@ public record ContainerImageMetadata(String imageName) {
|
||||
* Add this container image metadata to the given attributes.
|
||||
* @param attributes the attributes to add the metadata to
|
||||
*/
|
||||
public void addTo(AttributeAccessor attributes) {
|
||||
public void addTo(@Nullable AttributeAccessor attributes) {
|
||||
if (attributes != null) {
|
||||
attributes.setAttribute(NAME, this);
|
||||
}
|
||||
@@ -49,7 +51,7 @@ public record ContainerImageMetadata(String imageName) {
|
||||
* @param attributes the attributes to check
|
||||
* @return if metadata is present
|
||||
*/
|
||||
public static boolean isPresent(AttributeAccessor attributes) {
|
||||
public static boolean isPresent(@Nullable AttributeAccessor attributes) {
|
||||
return getFrom(attributes) != null;
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ public record ContainerImageMetadata(String imageName) {
|
||||
* @param attributes the attributes
|
||||
* @return the metadata or {@code null}
|
||||
*/
|
||||
public static ContainerImageMetadata getFrom(AttributeAccessor attributes) {
|
||||
public static @Nullable ContainerImageMetadata getFrom(@Nullable AttributeAccessor attributes) {
|
||||
return (attributes != null) ? (ContainerImageMetadata) attributes.getAttribute(NAME) : null;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Support classes related to auto-configuration involving containers.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.container;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+5
-3
@@ -22,6 +22,8 @@ import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
@@ -92,7 +94,7 @@ public final class MessageSourceAutoConfiguration {
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
private Properties loadCommonMessages(List<Resource> resources) {
|
||||
private @Nullable Properties loadCommonMessages(@Nullable List<Resource> resources) {
|
||||
if (CollectionUtils.isEmpty(resources)) {
|
||||
return null;
|
||||
}
|
||||
@@ -135,7 +137,7 @@ public final class MessageSourceAutoConfiguration {
|
||||
return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll());
|
||||
}
|
||||
|
||||
private Resource[] getResources(ClassLoader classLoader, String name) {
|
||||
private Resource[] getResources(@Nullable ClassLoader classLoader, String name) {
|
||||
String target = name.replace('.', '/');
|
||||
try {
|
||||
return new PathMatchingResourcePatternResolver(classLoader)
|
||||
@@ -151,7 +153,7 @@ public final class MessageSourceAutoConfiguration {
|
||||
static class MessageSourceRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
hints.resources().registerPattern("messages.properties").registerPattern("messages_*.properties");
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -23,6 +23,8 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -49,7 +51,7 @@ public class MessageSourceProperties {
|
||||
/**
|
||||
* List of locale-independent property file resources containing common messages.
|
||||
*/
|
||||
private List<Resource> commonMessages;
|
||||
private @Nullable List<Resource> commonMessages;
|
||||
|
||||
/**
|
||||
* Message bundles encoding.
|
||||
@@ -61,7 +63,7 @@ public class MessageSourceProperties {
|
||||
* forever. If a duration suffix is not specified, seconds will be used.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration cacheDuration;
|
||||
private @Nullable Duration cacheDuration;
|
||||
|
||||
/**
|
||||
* Whether to fall back to the system Locale if no files for a specific Locale have
|
||||
@@ -98,11 +100,11 @@ public class MessageSourceProperties {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public Duration getCacheDuration() {
|
||||
public @Nullable Duration getCacheDuration() {
|
||||
return this.cacheDuration;
|
||||
}
|
||||
|
||||
public void setCacheDuration(Duration cacheDuration) {
|
||||
public void setCacheDuration(@Nullable Duration cacheDuration) {
|
||||
this.cacheDuration = cacheDuration;
|
||||
}
|
||||
|
||||
@@ -130,11 +132,11 @@ public class MessageSourceProperties {
|
||||
this.useCodeAsDefaultMessage = useCodeAsDefaultMessage;
|
||||
}
|
||||
|
||||
public List<Resource> getCommonMessages() {
|
||||
public @Nullable List<Resource> getCommonMessages() {
|
||||
return this.commonMessages;
|
||||
}
|
||||
|
||||
public void setCommonMessages(List<Resource> commonMessages) {
|
||||
public void setCommonMessages(@Nullable List<Resource> commonMessages) {
|
||||
this.commonMessages = commonMessages;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for the Spring context.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.context;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+8
-3
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.data;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -48,15 +50,18 @@ import org.springframework.data.util.Streamable;
|
||||
public abstract class AbstractRepositoryConfigurationSourceSupport
|
||||
implements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
|
||||
BeanNameGenerator importBeanNameGenerator) {
|
||||
@Nullable BeanNameGenerator importBeanNameGenerator) {
|
||||
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(
|
||||
getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);
|
||||
delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());
|
||||
@@ -68,7 +73,7 @@ public abstract class AbstractRepositoryConfigurationSourceSupport
|
||||
}
|
||||
|
||||
private AnnotationRepositoryConfigurationSource getConfigurationSource(BeanDefinitionRegistry registry,
|
||||
BeanNameGenerator importBeanNameGenerator) {
|
||||
@Nullable BeanNameGenerator importBeanNameGenerator) {
|
||||
AnnotationMetadata metadata = AnnotationMetadata.introspect(getConfiguration());
|
||||
return new AutoConfiguredAnnotationRepositoryConfigurationSource(metadata, getAnnotation(), this.resourceLoader,
|
||||
this.environment, registry, importBeanNameGenerator) {
|
||||
@@ -129,7 +134,7 @@ public abstract class AbstractRepositoryConfigurationSourceSupport
|
||||
|
||||
AutoConfiguredAnnotationRepositoryConfigurationSource(AnnotationMetadata metadata,
|
||||
Class<? extends Annotation> annotation, ResourceLoader resourceLoader, Environment environment,
|
||||
BeanDefinitionRegistry registry, BeanNameGenerator generator) {
|
||||
BeanDefinitionRegistry registry, @Nullable BeanNameGenerator generator) {
|
||||
super(metadata, annotation, resourceLoader, environment, registry, generator);
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -19,12 +19,15 @@ package org.springframework.boot.autoconfigure.data;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link SpringBootCondition} for controlling what type of Spring Data repositories are
|
||||
@@ -36,10 +39,14 @@ class OnRepositoryTypeCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnRepositoryType.class.getName(),
|
||||
true);
|
||||
RepositoryType configuredType = getTypeProperty(context.getEnvironment(), (String) attributes.get("store"));
|
||||
Map<String, @Nullable Object> attributes = metadata
|
||||
.getAnnotationAttributes(ConditionalOnRepositoryType.class.getName(), true);
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
String store = (String) attributes.get("store");
|
||||
Assert.state(store != null, "'store' must not be null");
|
||||
RepositoryType configuredType = getTypeProperty(context.getEnvironment(), store);
|
||||
RepositoryType requiredType = (RepositoryType) attributes.get("type");
|
||||
Assert.state(requiredType != null, "'requiredType' must not be null");
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnRepositoryType.class);
|
||||
if (configuredType == requiredType || configuredType == RepositoryType.AUTO) {
|
||||
return ConditionOutcome
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration base classes for Spring Data.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.data;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+14
-9
@@ -25,6 +25,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.InjectionPoint;
|
||||
@@ -74,7 +76,8 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause, String description) {
|
||||
protected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause,
|
||||
@Nullable String description) {
|
||||
if (cause.getNumberOfBeansFound() != 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -118,7 +121,9 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
}
|
||||
|
||||
private Class<?> extractBeanType(ResolvableType resolvableType) {
|
||||
return resolvableType.getRawClass();
|
||||
Class<?> rawClass = resolvableType.getRawClass();
|
||||
Assert.state(rawClass != null, "'rawClass' must not be null");
|
||||
return rawClass;
|
||||
}
|
||||
|
||||
private List<AutoConfigurationResult> getAutoConfigurationResults(NoSuchBeanDefinitionException cause) {
|
||||
@@ -140,7 +145,7 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
.toList();
|
||||
}
|
||||
|
||||
private MethodMetadata getFactoryMethodMetadata(String beanName) {
|
||||
private @Nullable MethodMetadata getFactoryMethodMetadata(String beanName) {
|
||||
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(beanName);
|
||||
if (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
|
||||
return annotatedBeanDefinition.getFactoryMethodMetadata();
|
||||
@@ -183,7 +188,7 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
}
|
||||
}
|
||||
|
||||
private InjectionPoint findInjectionPoint(Throwable failure) {
|
||||
private @Nullable InjectionPoint findInjectionPoint(Throwable failure) {
|
||||
UnsatisfiedDependencyException unsatisfiedDependencyException = findCause(failure,
|
||||
UnsatisfiedDependencyException.class);
|
||||
if (unsatisfiedDependencyException == null) {
|
||||
@@ -196,7 +201,7 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
|
||||
private final String className;
|
||||
|
||||
private final String methodName;
|
||||
private final @Nullable String methodName;
|
||||
|
||||
Source(String source) {
|
||||
String[] tokens = source.split("#");
|
||||
@@ -208,7 +213,7 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
return this.className;
|
||||
}
|
||||
|
||||
String getMethodName() {
|
||||
@Nullable String getMethodName() {
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
@@ -252,7 +257,7 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
}
|
||||
|
||||
private boolean hasName(MethodMetadata methodMetadata, String name) {
|
||||
Map<String, Object> attributes = methodMetadata.getAnnotationAttributes(Bean.class.getName());
|
||||
Map<String, @Nullable Object> attributes = methodMetadata.getAnnotationAttributes(Bean.class.getName());
|
||||
String[] candidates = (attributes != null) ? (String[]) attributes.get("name") : null;
|
||||
if (candidates != null) {
|
||||
for (String candidate : candidates) {
|
||||
@@ -309,11 +314,11 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
|
||||
private static class UserConfigurationResult {
|
||||
|
||||
private final MethodMetadata methodMetadata;
|
||||
private final @Nullable MethodMetadata methodMetadata;
|
||||
|
||||
private final boolean nullBean;
|
||||
|
||||
UserConfigurationResult(MethodMetadata methodMetadata, boolean nullBean) {
|
||||
UserConfigurationResult(@Nullable MethodMetadata methodMetadata, boolean nullBean) {
|
||||
this.methodMetadata = methodMetadata;
|
||||
this.nullBean = nullBean;
|
||||
}
|
||||
|
||||
+3
@@ -18,4 +18,7 @@
|
||||
* Internal {@link org.springframework.boot.diagnostics.FailureAnalyzer} implementations
|
||||
* related to auto-configuration.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.diagnostics.analyzer;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+1
@@ -139,6 +139,7 @@ public class EntityScanPackages {
|
||||
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
|
||||
AnnotationAttributes attributes = AnnotationAttributes
|
||||
.fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName()));
|
||||
Assert.state(attributes != null, "'attributes' must not be null");
|
||||
Set<String> packagesToScan = new LinkedHashSet<>();
|
||||
for (String basePackage : attributes.getStringArray("basePackages")) {
|
||||
String[] tokenized = StringUtils.tokenizeToStringArray(
|
||||
|
||||
+3
-1
@@ -72,7 +72,9 @@ public class EntityScanner {
|
||||
for (String basePackage : packages) {
|
||||
if (StringUtils.hasText(basePackage)) {
|
||||
for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
|
||||
entitySet.add(ClassUtils.forName(candidate.getBeanClassName(), this.context.getClassLoader()));
|
||||
String beanClassName = candidate.getBeanClassName();
|
||||
Assert.state(beanClassName != null, "'beanClassName' must not be null");
|
||||
entitySet.add(ClassUtils.forName(beanClassName, this.context.getClassLoader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* General purpose domain annotations and classes.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.domain;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
@@ -85,7 +87,7 @@ public final class ProjectInfoAutoConfiguration {
|
||||
return target;
|
||||
}
|
||||
|
||||
private Properties loadSource(Resource location, Charset encoding) throws IOException {
|
||||
private Properties loadSource(Resource location, @Nullable Charset encoding) throws IOException {
|
||||
if (encoding != null) {
|
||||
return PropertiesLoaderUtils.loadProperties(new EncodedResource(location, encoding));
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for project information.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.info;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+4
-1
@@ -34,6 +34,7 @@ import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
|
||||
import org.springframework.jmx.export.annotation.AnnotationMBeanExporter;
|
||||
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
|
||||
import org.springframework.jmx.support.MBeanServerFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -94,7 +95,9 @@ public final class JmxAutoConfiguration {
|
||||
MBeanServerFactoryBean factory = new MBeanServerFactoryBean();
|
||||
factory.setLocateExistingServerIfPossible(true);
|
||||
factory.afterPropertiesSet();
|
||||
return factory.getObject();
|
||||
MBeanServer mBeanServer = factory.getObject();
|
||||
Assert.state(mBeanServer != null, "'mBeanServer' must not be null");
|
||||
return mBeanServer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.jmx;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.jmx.support.RegistrationPolicy;
|
||||
|
||||
@@ -46,7 +48,7 @@ public class JmxProperties {
|
||||
/**
|
||||
* JMX domain name.
|
||||
*/
|
||||
private String defaultDomain;
|
||||
private @Nullable String defaultDomain;
|
||||
|
||||
/**
|
||||
* JMX Registration policy.
|
||||
@@ -77,11 +79,11 @@ public class JmxProperties {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public String getDefaultDomain() {
|
||||
public @Nullable String getDefaultDomain() {
|
||||
return this.defaultDomain;
|
||||
}
|
||||
|
||||
public void setDefaultDomain(String defaultDomain) {
|
||||
public void setDefaultDomain(@Nullable String defaultDomain) {
|
||||
this.defaultDomain = defaultDomain;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -21,6 +21,8 @@ import java.util.Hashtable;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -28,6 +30,7 @@ import org.springframework.jmx.export.metadata.JmxAttributeSource;
|
||||
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
|
||||
import org.springframework.jmx.support.JmxUtils;
|
||||
import org.springframework.jmx.support.ObjectNameManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -39,6 +42,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
public class ParentAwareNamingStrategy extends MetadataNamingStrategy implements ApplicationContextAware {
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private boolean ensureUniqueRuntimeObjectNames;
|
||||
@@ -62,7 +66,7 @@ public class ParentAwareNamingStrategy extends MetadataNamingStrategy implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
|
||||
public ObjectName getObjectName(Object managedBean, @Nullable String beanKey) throws MalformedObjectNameException {
|
||||
ObjectName name = super.getObjectName(managedBean, beanKey);
|
||||
if (this.ensureUniqueRuntimeObjectNames) {
|
||||
return JmxUtils.appendIdentityToObjectName(name, managedBean);
|
||||
@@ -73,12 +77,15 @@ public class ParentAwareNamingStrategy extends MetadataNamingStrategy implements
|
||||
return name;
|
||||
}
|
||||
|
||||
private boolean parentContextContainsSameBean(ApplicationContext context, String beanKey) {
|
||||
private boolean parentContextContainsSameBean(ApplicationContext context, @Nullable String beanKey) {
|
||||
if (context.getParent() == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
this.applicationContext.getParent().getBean(beanKey);
|
||||
ApplicationContext parent = this.applicationContext.getParent();
|
||||
Assert.state(parent != null, "'parent' must not be null");
|
||||
Assert.state(beanKey != null, "'beanKey' must not be null");
|
||||
parent.getBean(beanKey);
|
||||
return true;
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for JMX.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.jmx;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.logging;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
@@ -124,7 +126,7 @@ public class ConditionEvaluationReportLoggingListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSourceType(Class<?> sourceType) {
|
||||
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.logging;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
@@ -31,7 +33,8 @@ import org.springframework.boot.logging.LogLevel;
|
||||
class ConditionEvaluationReportLoggingProcessor implements BeanFactoryInitializationAotProcessor {
|
||||
|
||||
@Override
|
||||
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
|
||||
public @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
logConditionEvaluationReport(beanFactory);
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -133,6 +134,7 @@ public class ConditionEvaluationReportMessage {
|
||||
Map<String, ConditionAndOutcomes> result = new LinkedHashMap<>();
|
||||
for (String shortName : shortNames) {
|
||||
List<String> fullyQualifiedNames = map.get(shortName);
|
||||
Assert.state(fullyQualifiedNames != null, "'fullyQualifiedNames' must not be null");
|
||||
if (fullyQualifiedNames.size() > 1) {
|
||||
fullyQualifiedNames
|
||||
.forEach((fullyQualifiedName) -> result.put(fullyQualifiedName, outcomes.get(fullyQualifiedName)));
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for logging.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.logging;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -19,4 +19,7 @@
|
||||
*
|
||||
* @see org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Capabilities to preinitialize code in the background to improve startup performance.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.preinitialize;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+5
-3
@@ -26,6 +26,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
@@ -53,7 +54,7 @@ public class ConnectionDetailsFactories {
|
||||
* @param classLoader the class loader used to load factories
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public ConnectionDetailsFactories(ClassLoader classLoader) {
|
||||
public ConnectionDetailsFactories(@Nullable ClassLoader classLoader) {
|
||||
this(SpringFactoriesLoader.forDefaultResourceLocation(classLoader));
|
||||
}
|
||||
|
||||
@@ -126,9 +127,10 @@ public class ConnectionDetailsFactories {
|
||||
ConnectionDetailsFactory<S, D> factory) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <S, D extends ConnectionDetails> Registration<S, D> get(ConnectionDetailsFactory<S, D> factory) {
|
||||
private static <S, D extends ConnectionDetails> @Nullable Registration<S, D> get(
|
||||
ConnectionDetailsFactory<S, D> factory) {
|
||||
ResolvableType type = ResolvableType.forClass(ConnectionDetailsFactory.class, factory.getClass());
|
||||
Class<?>[] generics = type.resolveGenerics();
|
||||
@Nullable Class<?>[] generics = type.resolveGenerics();
|
||||
Class<S> sourceType = (Class<S>) generics[0];
|
||||
Class<D> connectionDetailsType = (Class<D>) generics[1];
|
||||
return (sourceType != null && connectionDetailsType != null)
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.service.connection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A factory to create {@link ConnectionDetails} from a given {@code source}.
|
||||
* Implementations should be registered in {@code META-INF/spring.factories}.
|
||||
@@ -36,6 +38,6 @@ public interface ConnectionDetailsFactory<S, D extends ConnectionDetails> {
|
||||
* @param source the source
|
||||
* @return the connection details or {@code null}
|
||||
*/
|
||||
D getConnectionDetails(S source);
|
||||
@Nullable D getConnectionDetails(S source);
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Support for service connections that affect auto-configuration.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.service.connection;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+4
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.ssl.pem.PemContent;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -33,7 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Phillip Webb
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
record BundleContentProperty(String name, String value) {
|
||||
record BundleContentProperty(String name, @Nullable String value) {
|
||||
|
||||
/**
|
||||
* Return if the property value is PEM content.
|
||||
@@ -54,6 +56,7 @@ record BundleContentProperty(String name, String value) {
|
||||
Path toWatchPath(ResourceLoader resourceLoader) {
|
||||
try {
|
||||
Assert.state(!isPemContent(), "Value contains PEM content");
|
||||
Assert.state(this.value != null, "Value must not be null");
|
||||
Resource resource = resourceLoader.getResource(this.value);
|
||||
if (!resource.isFile()) {
|
||||
throw new BundleContentNotWatchableException(this);
|
||||
|
||||
+10
-7
@@ -26,6 +26,8 @@ import java.security.cert.Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -47,17 +49,18 @@ class CertificateMatcher {
|
||||
|
||||
private final Signature signature;
|
||||
|
||||
private final byte[] generatedSignature;
|
||||
private final byte @Nullable [] generatedSignature;
|
||||
|
||||
CertificateMatcher(PrivateKey privateKey) {
|
||||
Assert.notNull(privateKey, "'privateKey' must not be null");
|
||||
this.privateKey = privateKey;
|
||||
this.signature = createSignature(privateKey);
|
||||
Assert.state(this.signature != null, "Failed to create signature");
|
||||
this.generatedSignature = sign(this.signature, privateKey);
|
||||
Signature signature = createSignature(privateKey);
|
||||
Assert.state(signature != null, "Failed to create signature");
|
||||
this.signature = signature;
|
||||
this.generatedSignature = sign(signature, privateKey);
|
||||
}
|
||||
|
||||
private Signature createSignature(PrivateKey privateKey) {
|
||||
private @Nullable Signature createSignature(PrivateKey privateKey) {
|
||||
try {
|
||||
String algorithm = getSignatureAlgorithm(privateKey);
|
||||
return (algorithm != null) ? Signature.getInstance(algorithm) : null;
|
||||
@@ -67,7 +70,7 @@ class CertificateMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSignatureAlgorithm(PrivateKey privateKey) {
|
||||
private static @Nullable String getSignatureAlgorithm(PrivateKey privateKey) {
|
||||
// https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html#signature-algorithms
|
||||
// https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html#keypairgenerator-algorithms
|
||||
return switch (privateKey.getAlgorithm()) {
|
||||
@@ -103,7 +106,7 @@ class CertificateMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] sign(Signature signature, PrivateKey privateKey) {
|
||||
private static byte @Nullable [] sign(Signature signature, PrivateKey privateKey) {
|
||||
try {
|
||||
signature.initSign(privateKey);
|
||||
signature.update(DATA);
|
||||
|
||||
+3
-1
@@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -57,7 +58,7 @@ class FileWatcher implements Closeable {
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
private WatcherThread thread;
|
||||
private @Nullable WatcherThread thread;
|
||||
|
||||
/**
|
||||
* Create a new {@link FileWatcher} instance.
|
||||
@@ -241,6 +242,7 @@ class FileWatcher implements Closeable {
|
||||
Path directory = (Path) key.watchable();
|
||||
for (WatchEvent<?> event : key.pollEvents()) {
|
||||
Path file = directory.resolve((Path) event.context());
|
||||
Assert.state(registrations != null, "'registrations' must not be null");
|
||||
for (Registration registration : registrations) {
|
||||
if (registration.manages(file)) {
|
||||
actions.add(registration.action());
|
||||
|
||||
+14
-12
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.ssl.jks.JksSslStoreBundle;
|
||||
|
||||
/**
|
||||
@@ -54,52 +56,52 @@ public class JksSslBundleProperties extends SslBundleProperties {
|
||||
/**
|
||||
* Type of the store to create, e.g. JKS.
|
||||
*/
|
||||
private String type;
|
||||
private @Nullable String type;
|
||||
|
||||
/**
|
||||
* Provider for the store.
|
||||
*/
|
||||
private String provider;
|
||||
private @Nullable String provider;
|
||||
|
||||
/**
|
||||
* Location of the resource containing the store content.
|
||||
*/
|
||||
private String location;
|
||||
private @Nullable String location;
|
||||
|
||||
/**
|
||||
* Password used to access the store.
|
||||
*/
|
||||
private String password;
|
||||
private @Nullable String password;
|
||||
|
||||
public String getType() {
|
||||
public @Nullable String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
public void setType(@Nullable String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
public @Nullable String getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
public void setProvider(@Nullable String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
public @Nullable String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
public void setLocation(@Nullable String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
public @Nullable String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
public void setPassword(@Nullable String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
+14
-12
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.ssl.pem.PemSslStoreBundle;
|
||||
|
||||
/**
|
||||
@@ -55,57 +57,57 @@ public class PemSslBundleProperties extends SslBundleProperties {
|
||||
/**
|
||||
* Type of the store to create, e.g. JKS.
|
||||
*/
|
||||
private String type;
|
||||
private @Nullable String type;
|
||||
|
||||
/**
|
||||
* Location or content of the certificate or certificate chain in PEM format.
|
||||
*/
|
||||
private String certificate;
|
||||
private @Nullable String certificate;
|
||||
|
||||
/**
|
||||
* Location or content of the private key in PEM format.
|
||||
*/
|
||||
private String privateKey;
|
||||
private @Nullable String privateKey;
|
||||
|
||||
/**
|
||||
* Password used to decrypt an encrypted private key.
|
||||
*/
|
||||
private String privateKeyPassword;
|
||||
private @Nullable String privateKeyPassword;
|
||||
|
||||
/**
|
||||
* Whether to verify that the private key matches the public key.
|
||||
*/
|
||||
private boolean verifyKeys;
|
||||
|
||||
public String getType() {
|
||||
public @Nullable String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
public void setType(@Nullable String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getCertificate() {
|
||||
public @Nullable String getCertificate() {
|
||||
return this.certificate;
|
||||
}
|
||||
|
||||
public void setCertificate(String certificate) {
|
||||
public void setCertificate(@Nullable String certificate) {
|
||||
this.certificate = certificate;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
public @Nullable String getPrivateKey() {
|
||||
return this.privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
public void setPrivateKey(@Nullable String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getPrivateKeyPassword() {
|
||||
public @Nullable String getPrivateKeyPassword() {
|
||||
return this.privateKeyPassword;
|
||||
}
|
||||
|
||||
public void setPrivateKeyPassword(String privateKeyPassword) {
|
||||
public void setPrivateKeyPassword(@Nullable String privateKeyPassword) {
|
||||
this.privateKeyPassword = privateKeyPassword;
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -16,6 +16,12 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ssl.SslBundleProperties.Key;
|
||||
import org.springframework.boot.io.ApplicationResourceLoader;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
@@ -60,11 +66,11 @@ public final class PropertiesSslBundle implements SslBundle {
|
||||
this.managers = SslManagerBundle.from(this.stores, this.key);
|
||||
}
|
||||
|
||||
private static SslBundleKey asSslKeyReference(Key key) {
|
||||
private static SslBundleKey asSslKeyReference(@Nullable Key key) {
|
||||
return (key != null) ? SslBundleKey.of(key.getPassword(), key.getAlias()) : SslBundleKey.NONE;
|
||||
}
|
||||
|
||||
private static SslOptions asSslOptions(SslBundleProperties.Options options) {
|
||||
private static SslOptions asSslOptions(SslBundleProperties.@Nullable Options options) {
|
||||
return (options != null) ? SslOptions.of(options.getCiphers(), options.getEnabledProtocols()) : SslOptions.NONE;
|
||||
}
|
||||
|
||||
@@ -120,13 +126,18 @@ public final class PropertiesSslBundle implements SslBundle {
|
||||
return new PropertiesSslBundle(storeBundle, properties);
|
||||
}
|
||||
|
||||
private static PemSslStore getPemSslStore(String propertyName, PemSslBundleProperties.Store properties,
|
||||
private static @Nullable PemSslStore getPemSslStore(String propertyName, PemSslBundleProperties.Store properties,
|
||||
ResourceLoader resourceLoader) {
|
||||
PemSslStoreDetails details = asPemSslStoreDetails(properties);
|
||||
PemSslStore pemSslStore = PemSslStore.load(details, resourceLoader);
|
||||
if (properties.isVerifyKeys()) {
|
||||
CertificateMatcher certificateMatcher = new CertificateMatcher(pemSslStore.privateKey());
|
||||
Assert.state(certificateMatcher.matchesAny(pemSslStore.certificates()),
|
||||
Assert.state(pemSslStore != null, "'pemSslStore' must not be null");
|
||||
PrivateKey privateKey = pemSslStore.privateKey();
|
||||
Assert.state(privateKey != null, "'privateKey' must not be null");
|
||||
CertificateMatcher certificateMatcher = new CertificateMatcher(privateKey);
|
||||
List<X509Certificate> certificates = pemSslStore.certificates();
|
||||
Assert.state(certificates != null, "'certificates' must not be null");
|
||||
Assert.state(certificateMatcher.matchesAny(certificates),
|
||||
() -> "Private key in %s matches none of the certificates in the chain".formatted(propertyName));
|
||||
}
|
||||
return pemSslStore;
|
||||
|
||||
+14
-12
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
/**
|
||||
@@ -79,26 +81,26 @@ public abstract class SslBundleProperties {
|
||||
/**
|
||||
* Supported SSL ciphers.
|
||||
*/
|
||||
private Set<String> ciphers;
|
||||
private @Nullable Set<String> ciphers;
|
||||
|
||||
/**
|
||||
* Enabled SSL protocols.
|
||||
*/
|
||||
private Set<String> enabledProtocols;
|
||||
private @Nullable Set<String> enabledProtocols;
|
||||
|
||||
public Set<String> getCiphers() {
|
||||
public @Nullable Set<String> getCiphers() {
|
||||
return this.ciphers;
|
||||
}
|
||||
|
||||
public void setCiphers(Set<String> ciphers) {
|
||||
public void setCiphers(@Nullable Set<String> ciphers) {
|
||||
this.ciphers = ciphers;
|
||||
}
|
||||
|
||||
public Set<String> getEnabledProtocols() {
|
||||
public @Nullable Set<String> getEnabledProtocols() {
|
||||
return this.enabledProtocols;
|
||||
}
|
||||
|
||||
public void setEnabledProtocols(Set<String> enabledProtocols) {
|
||||
public void setEnabledProtocols(@Nullable Set<String> enabledProtocols) {
|
||||
this.enabledProtocols = enabledProtocols;
|
||||
}
|
||||
|
||||
@@ -109,26 +111,26 @@ public abstract class SslBundleProperties {
|
||||
/**
|
||||
* The password used to access the key in the key store.
|
||||
*/
|
||||
private String password;
|
||||
private @Nullable String password;
|
||||
|
||||
/**
|
||||
* The alias that identifies the key in the key store.
|
||||
*/
|
||||
private String alias;
|
||||
private @Nullable String alias;
|
||||
|
||||
public String getPassword() {
|
||||
public @Nullable String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
public void setPassword(@Nullable String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
public @Nullable String getAlias() {
|
||||
return this.alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
public void setAlias(@Nullable String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for SSL bundles.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+8
-6
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.task;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
@@ -86,7 +88,7 @@ public class TaskExecutionProperties {
|
||||
* Set the maximum number of parallel accesses allowed. -1 indicates no
|
||||
* concurrency limit at all.
|
||||
*/
|
||||
private Integer concurrencyLimit;
|
||||
private @Nullable Integer concurrencyLimit;
|
||||
|
||||
public boolean isRejectTasksWhenLimitReached() {
|
||||
return this.rejectTasksWhenLimitReached;
|
||||
@@ -96,11 +98,11 @@ public class TaskExecutionProperties {
|
||||
this.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;
|
||||
}
|
||||
|
||||
public Integer getConcurrencyLimit() {
|
||||
public @Nullable Integer getConcurrencyLimit() {
|
||||
return this.concurrencyLimit;
|
||||
}
|
||||
|
||||
public void setConcurrencyLimit(Integer concurrencyLimit) {
|
||||
public void setConcurrencyLimit(@Nullable Integer concurrencyLimit) {
|
||||
this.concurrencyLimit = concurrencyLimit;
|
||||
}
|
||||
|
||||
@@ -215,7 +217,7 @@ public class TaskExecutionProperties {
|
||||
/**
|
||||
* Maximum time the executor should wait for remaining tasks to complete.
|
||||
*/
|
||||
private Duration awaitTerminationPeriod;
|
||||
private @Nullable Duration awaitTerminationPeriod;
|
||||
|
||||
public boolean isAwaitTermination() {
|
||||
return this.awaitTermination;
|
||||
@@ -225,11 +227,11 @@ public class TaskExecutionProperties {
|
||||
this.awaitTermination = awaitTermination;
|
||||
}
|
||||
|
||||
public Duration getAwaitTerminationPeriod() {
|
||||
public @Nullable Duration getAwaitTerminationPeriod() {
|
||||
return this.awaitTerminationPeriod;
|
||||
}
|
||||
|
||||
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
|
||||
public void setAwaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {
|
||||
this.awaitTerminationPeriod = awaitTerminationPeriod;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.task;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
@@ -54,7 +56,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
*/
|
||||
class TaskExecutorConfigurations {
|
||||
|
||||
private static TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {
|
||||
private static @Nullable TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {
|
||||
List<TaskDecorator> taskDecorators = taskDecorator.orderedStream().toList();
|
||||
if (taskDecorators.size() == 1) {
|
||||
return taskDecorators.get(0);
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.task;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -45,7 +47,7 @@ import org.springframework.scheduling.config.TaskManagementConfigUtils;
|
||||
*/
|
||||
class TaskSchedulingConfigurations {
|
||||
|
||||
private static TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {
|
||||
private static @Nullable TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {
|
||||
List<TaskDecorator> taskDecorators = taskDecorator.orderedStream().toList();
|
||||
if (taskDecorators.size() == 1) {
|
||||
return taskDecorators.get(0);
|
||||
|
||||
+8
-6
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.task;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
@@ -84,13 +86,13 @@ public class TaskSchedulingProperties {
|
||||
* Set the maximum number of parallel accesses allowed. -1 indicates no
|
||||
* concurrency limit at all.
|
||||
*/
|
||||
private Integer concurrencyLimit;
|
||||
private @Nullable Integer concurrencyLimit;
|
||||
|
||||
public Integer getConcurrencyLimit() {
|
||||
public @Nullable Integer getConcurrencyLimit() {
|
||||
return this.concurrencyLimit;
|
||||
}
|
||||
|
||||
public void setConcurrencyLimit(Integer concurrencyLimit) {
|
||||
public void setConcurrencyLimit(@Nullable Integer concurrencyLimit) {
|
||||
this.concurrencyLimit = concurrencyLimit;
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ public class TaskSchedulingProperties {
|
||||
/**
|
||||
* Maximum time the executor should wait for remaining tasks to complete.
|
||||
*/
|
||||
private Duration awaitTerminationPeriod;
|
||||
private @Nullable Duration awaitTerminationPeriod;
|
||||
|
||||
public boolean isAwaitTermination() {
|
||||
return this.awaitTermination;
|
||||
@@ -116,11 +118,11 @@ public class TaskSchedulingProperties {
|
||||
this.awaitTermination = awaitTermination;
|
||||
}
|
||||
|
||||
public Duration getAwaitTerminationPeriod() {
|
||||
public @Nullable Duration getAwaitTerminationPeriod() {
|
||||
return this.awaitTerminationPeriod;
|
||||
}
|
||||
|
||||
public void setAwaitTerminationPeriod(Duration awaitTerminationPeriod) {
|
||||
public void setAwaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {
|
||||
this.awaitTerminationPeriod = awaitTerminationPeriod;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for task execution and scheduling.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.task;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+18
-8
@@ -23,6 +23,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -72,7 +74,14 @@ public class TemplateAvailabilityProviders {
|
||||
* @param applicationContext the source application context
|
||||
*/
|
||||
public TemplateAvailabilityProviders(ApplicationContext applicationContext) {
|
||||
this((applicationContext != null) ? applicationContext.getClassLoader() : null);
|
||||
this(getClassLoader(applicationContext));
|
||||
}
|
||||
|
||||
private static ClassLoader getClassLoader(ApplicationContext applicationContext) {
|
||||
Assert.notNull(applicationContext, "'applicationContext' must not be null");
|
||||
ClassLoader classLoader = applicationContext.getClassLoader();
|
||||
Assert.state(classLoader != null, "'classLoader' must not be null");
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,10 +116,11 @@ public class TemplateAvailabilityProviders {
|
||||
* @param applicationContext the application context
|
||||
* @return a {@link TemplateAvailabilityProvider} or null
|
||||
*/
|
||||
public TemplateAvailabilityProvider getProvider(String view, ApplicationContext applicationContext) {
|
||||
public @Nullable TemplateAvailabilityProvider getProvider(String view, ApplicationContext applicationContext) {
|
||||
Assert.notNull(applicationContext, "'applicationContext' must not be null");
|
||||
return getProvider(view, applicationContext.getEnvironment(), applicationContext.getClassLoader(),
|
||||
applicationContext);
|
||||
ClassLoader classLoader = applicationContext.getClassLoader();
|
||||
Assert.state(classLoader != null, "'classLoader' must not be null");
|
||||
return getProvider(view, applicationContext.getEnvironment(), classLoader, applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,8 +131,8 @@ public class TemplateAvailabilityProviders {
|
||||
* @param resourceLoader the resource loader
|
||||
* @return a {@link TemplateAvailabilityProvider} or null
|
||||
*/
|
||||
public TemplateAvailabilityProvider getProvider(String view, Environment environment, ClassLoader classLoader,
|
||||
ResourceLoader resourceLoader) {
|
||||
public @Nullable TemplateAvailabilityProvider getProvider(String view, Environment environment,
|
||||
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||
Assert.notNull(view, "'view' must not be null");
|
||||
Assert.notNull(environment, "'environment' must not be null");
|
||||
Assert.notNull(classLoader, "'classLoader' must not be null");
|
||||
@@ -143,8 +153,8 @@ public class TemplateAvailabilityProviders {
|
||||
return (provider != NONE) ? provider : null;
|
||||
}
|
||||
|
||||
private TemplateAvailabilityProvider findProvider(String view, Environment environment, ClassLoader classLoader,
|
||||
ResourceLoader resourceLoader) {
|
||||
private @Nullable TemplateAvailabilityProvider findProvider(String view, Environment environment,
|
||||
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||
for (TemplateAvailabilityProvider candidate : this.providers) {
|
||||
if (candidate.isTemplateAvailable(view, environment, classLoader, resourceLoader)) {
|
||||
return candidate;
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.template;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
|
||||
@@ -27,7 +29,7 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
class TemplateRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
hints.resources().registerPatternIfPresent(classLoader, "templates", (hint) -> hint.includes("templates/**"));
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Base classes for template Auto-configuration.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.template;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+9
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
@@ -24,6 +26,7 @@ import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -64,8 +67,13 @@ class OnEnabledResourceChainCondition extends SpringBootCondition {
|
||||
return ConditionOutcome.noMatch(message.because("disabled"));
|
||||
}
|
||||
|
||||
private Boolean getEnabledProperty(ConfigurableEnvironment environment, String key, Boolean defaultValue) {
|
||||
@Contract("_, _, !null -> !null")
|
||||
private @Nullable Boolean getEnabledProperty(ConfigurableEnvironment environment, String key,
|
||||
@Nullable Boolean defaultValue) {
|
||||
String name = "spring.web.resources.chain." + key + "enabled";
|
||||
if (defaultValue == null) {
|
||||
return environment.getProperty(name, Boolean.class);
|
||||
}
|
||||
return environment.getProperty(name, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
+49
-46
@@ -21,6 +21,8 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.convert.DurationUnit;
|
||||
@@ -39,7 +41,7 @@ public class WebProperties {
|
||||
* Locale to use. By default, this locale is overridden by the "Accept-Language"
|
||||
* header.
|
||||
*/
|
||||
private Locale locale;
|
||||
private @Nullable Locale locale;
|
||||
|
||||
/**
|
||||
* Define how the locale should be resolved.
|
||||
@@ -48,11 +50,11 @@ public class WebProperties {
|
||||
|
||||
private final Resources resources = new Resources();
|
||||
|
||||
public Locale getLocale() {
|
||||
public @Nullable Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
public void setLocale(@Nullable Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@@ -155,7 +157,7 @@ public class WebProperties {
|
||||
* Whether to enable the Spring Resource Handling chain. By default, disabled
|
||||
* unless at least one strategy has been enabled.
|
||||
*/
|
||||
private Boolean enabled;
|
||||
private @Nullable Boolean enabled;
|
||||
|
||||
/**
|
||||
* Whether to enable caching in the Resource chain.
|
||||
@@ -177,7 +179,7 @@ public class WebProperties {
|
||||
* @return whether the resource chain is enabled or {@code null} if no
|
||||
* specified settings are present.
|
||||
*/
|
||||
public Boolean getEnabled() {
|
||||
public @Nullable Boolean getEnabled() {
|
||||
return getEnabled(getStrategy().getFixed().isEnabled(), getStrategy().getContent().isEnabled(),
|
||||
this.enabled);
|
||||
}
|
||||
@@ -213,7 +215,8 @@ public class WebProperties {
|
||||
this.customized = true;
|
||||
}
|
||||
|
||||
static Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled, Boolean chainEnabled) {
|
||||
static @Nullable Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled,
|
||||
@Nullable Boolean chainEnabled) {
|
||||
return (fixedEnabled || contentEnabled) ? Boolean.TRUE : chainEnabled;
|
||||
}
|
||||
|
||||
@@ -299,7 +302,7 @@ public class WebProperties {
|
||||
/**
|
||||
* Version string to use for the fixed Version Strategy.
|
||||
*/
|
||||
private String version;
|
||||
private @Nullable String version;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
@@ -319,11 +322,11 @@ public class WebProperties {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
public @Nullable String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
public void setVersion(@Nullable String version) {
|
||||
this.customized = true;
|
||||
this.version = version;
|
||||
}
|
||||
@@ -351,7 +354,7 @@ public class WebProperties {
|
||||
* by the 'spring.web.resources.cache.cachecontrol' properties.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration period;
|
||||
private @Nullable Duration period;
|
||||
|
||||
/**
|
||||
* Cache control HTTP headers, only allows valid directive combinations.
|
||||
@@ -365,11 +368,11 @@ public class WebProperties {
|
||||
*/
|
||||
private boolean useLastModified = true;
|
||||
|
||||
public Duration getPeriod() {
|
||||
public @Nullable Duration getPeriod() {
|
||||
return this.period;
|
||||
}
|
||||
|
||||
public void setPeriod(Duration period) {
|
||||
public void setPeriod(@Nullable Duration period) {
|
||||
this.customized = true;
|
||||
this.period = period;
|
||||
}
|
||||
@@ -402,169 +405,169 @@ public class WebProperties {
|
||||
* suffix is not specified.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration maxAge;
|
||||
private @Nullable Duration maxAge;
|
||||
|
||||
/**
|
||||
* Indicate that the cached response can be reused only if re-validated
|
||||
* with the server.
|
||||
*/
|
||||
private Boolean noCache;
|
||||
private @Nullable Boolean noCache;
|
||||
|
||||
/**
|
||||
* Indicate to not cache the response in any case.
|
||||
*/
|
||||
private Boolean noStore;
|
||||
private @Nullable Boolean noStore;
|
||||
|
||||
/**
|
||||
* Indicate that once it has become stale, a cache must not use the
|
||||
* response without re-validating it with the server.
|
||||
*/
|
||||
private Boolean mustRevalidate;
|
||||
private @Nullable Boolean mustRevalidate;
|
||||
|
||||
/**
|
||||
* Indicate intermediaries (caches and others) that they should not
|
||||
* transform the response content.
|
||||
*/
|
||||
private Boolean noTransform;
|
||||
private @Nullable Boolean noTransform;
|
||||
|
||||
/**
|
||||
* Indicate that any cache may store the response.
|
||||
*/
|
||||
private Boolean cachePublic;
|
||||
private @Nullable Boolean cachePublic;
|
||||
|
||||
/**
|
||||
* Indicate that the response message is intended for a single user and
|
||||
* must not be stored by a shared cache.
|
||||
*/
|
||||
private Boolean cachePrivate;
|
||||
private @Nullable Boolean cachePrivate;
|
||||
|
||||
/**
|
||||
* Same meaning as the "must-revalidate" directive, except that it does
|
||||
* not apply to private caches.
|
||||
*/
|
||||
private Boolean proxyRevalidate;
|
||||
private @Nullable Boolean proxyRevalidate;
|
||||
|
||||
/**
|
||||
* Maximum time the response can be served after it becomes stale, in
|
||||
* seconds if no duration suffix is not specified.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration staleWhileRevalidate;
|
||||
private @Nullable Duration staleWhileRevalidate;
|
||||
|
||||
/**
|
||||
* Maximum time the response may be used when errors are encountered, in
|
||||
* seconds if no duration suffix is not specified.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration staleIfError;
|
||||
private @Nullable Duration staleIfError;
|
||||
|
||||
/**
|
||||
* Maximum time the response should be cached by shared caches, in seconds
|
||||
* if no duration suffix is not specified.
|
||||
*/
|
||||
@DurationUnit(ChronoUnit.SECONDS)
|
||||
private Duration sMaxAge;
|
||||
private @Nullable Duration sMaxAge;
|
||||
|
||||
public Duration getMaxAge() {
|
||||
public @Nullable Duration getMaxAge() {
|
||||
return this.maxAge;
|
||||
}
|
||||
|
||||
public void setMaxAge(Duration maxAge) {
|
||||
public void setMaxAge(@Nullable Duration maxAge) {
|
||||
this.customized = true;
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
public Boolean getNoCache() {
|
||||
public @Nullable Boolean getNoCache() {
|
||||
return this.noCache;
|
||||
}
|
||||
|
||||
public void setNoCache(Boolean noCache) {
|
||||
public void setNoCache(@Nullable Boolean noCache) {
|
||||
this.customized = true;
|
||||
this.noCache = noCache;
|
||||
}
|
||||
|
||||
public Boolean getNoStore() {
|
||||
public @Nullable Boolean getNoStore() {
|
||||
return this.noStore;
|
||||
}
|
||||
|
||||
public void setNoStore(Boolean noStore) {
|
||||
public void setNoStore(@Nullable Boolean noStore) {
|
||||
this.customized = true;
|
||||
this.noStore = noStore;
|
||||
}
|
||||
|
||||
public Boolean getMustRevalidate() {
|
||||
public @Nullable Boolean getMustRevalidate() {
|
||||
return this.mustRevalidate;
|
||||
}
|
||||
|
||||
public void setMustRevalidate(Boolean mustRevalidate) {
|
||||
public void setMustRevalidate(@Nullable Boolean mustRevalidate) {
|
||||
this.customized = true;
|
||||
this.mustRevalidate = mustRevalidate;
|
||||
}
|
||||
|
||||
public Boolean getNoTransform() {
|
||||
public @Nullable Boolean getNoTransform() {
|
||||
return this.noTransform;
|
||||
}
|
||||
|
||||
public void setNoTransform(Boolean noTransform) {
|
||||
public void setNoTransform(@Nullable Boolean noTransform) {
|
||||
this.customized = true;
|
||||
this.noTransform = noTransform;
|
||||
}
|
||||
|
||||
public Boolean getCachePublic() {
|
||||
public @Nullable Boolean getCachePublic() {
|
||||
return this.cachePublic;
|
||||
}
|
||||
|
||||
public void setCachePublic(Boolean cachePublic) {
|
||||
public void setCachePublic(@Nullable Boolean cachePublic) {
|
||||
this.customized = true;
|
||||
this.cachePublic = cachePublic;
|
||||
}
|
||||
|
||||
public Boolean getCachePrivate() {
|
||||
public @Nullable Boolean getCachePrivate() {
|
||||
return this.cachePrivate;
|
||||
}
|
||||
|
||||
public void setCachePrivate(Boolean cachePrivate) {
|
||||
public void setCachePrivate(@Nullable Boolean cachePrivate) {
|
||||
this.customized = true;
|
||||
this.cachePrivate = cachePrivate;
|
||||
}
|
||||
|
||||
public Boolean getProxyRevalidate() {
|
||||
public @Nullable Boolean getProxyRevalidate() {
|
||||
return this.proxyRevalidate;
|
||||
}
|
||||
|
||||
public void setProxyRevalidate(Boolean proxyRevalidate) {
|
||||
public void setProxyRevalidate(@Nullable Boolean proxyRevalidate) {
|
||||
this.customized = true;
|
||||
this.proxyRevalidate = proxyRevalidate;
|
||||
}
|
||||
|
||||
public Duration getStaleWhileRevalidate() {
|
||||
public @Nullable Duration getStaleWhileRevalidate() {
|
||||
return this.staleWhileRevalidate;
|
||||
}
|
||||
|
||||
public void setStaleWhileRevalidate(Duration staleWhileRevalidate) {
|
||||
public void setStaleWhileRevalidate(@Nullable Duration staleWhileRevalidate) {
|
||||
this.customized = true;
|
||||
this.staleWhileRevalidate = staleWhileRevalidate;
|
||||
}
|
||||
|
||||
public Duration getStaleIfError() {
|
||||
public @Nullable Duration getStaleIfError() {
|
||||
return this.staleIfError;
|
||||
}
|
||||
|
||||
public void setStaleIfError(Duration staleIfError) {
|
||||
public void setStaleIfError(@Nullable Duration staleIfError) {
|
||||
this.customized = true;
|
||||
this.staleIfError = staleIfError;
|
||||
}
|
||||
|
||||
public Duration getSMaxAge() {
|
||||
public @Nullable Duration getSMaxAge() {
|
||||
return this.sMaxAge;
|
||||
}
|
||||
|
||||
public void setSMaxAge(Duration sMaxAge) {
|
||||
public void setSMaxAge(@Nullable Duration sMaxAge) {
|
||||
this.customized = true;
|
||||
this.sMaxAge = sMaxAge;
|
||||
}
|
||||
|
||||
public CacheControl toHttpCacheControl() {
|
||||
public @Nullable CacheControl toHttpCacheControl() {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
CacheControl control = createCacheControl();
|
||||
map.from(this::getMustRevalidate).whenTrue().toCall(control::mustRevalidate);
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
|
||||
@@ -33,7 +35,7 @@ public class WebResourcesRuntimeHints implements RuntimeHintsRegistrar {
|
||||
"public/");
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
ClassLoader classLoaderToUse = (classLoader != null) ? classLoader : getClass().getClassLoader();
|
||||
String[] locations = DEFAULT_LOCATIONS.stream()
|
||||
.filter((candidate) -> classLoaderToUse.getResource(candidate) != null)
|
||||
|
||||
+11
-9
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.web.format;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.ResolverStyle;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -30,13 +32,13 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class DateTimeFormatters {
|
||||
|
||||
private DateTimeFormatter dateFormatter;
|
||||
private @Nullable DateTimeFormatter dateFormatter;
|
||||
|
||||
private String datePattern;
|
||||
private @Nullable String datePattern;
|
||||
|
||||
private DateTimeFormatter timeFormatter;
|
||||
private @Nullable DateTimeFormatter timeFormatter;
|
||||
|
||||
private DateTimeFormatter dateTimeFormatter;
|
||||
private @Nullable DateTimeFormatter dateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Configures the date format using the given {@code pattern}.
|
||||
@@ -77,19 +79,19 @@ public class DateTimeFormatters {
|
||||
return this;
|
||||
}
|
||||
|
||||
DateTimeFormatter getDateFormatter() {
|
||||
@Nullable DateTimeFormatter getDateFormatter() {
|
||||
return this.dateFormatter;
|
||||
}
|
||||
|
||||
String getDatePattern() {
|
||||
@Nullable String getDatePattern() {
|
||||
return this.datePattern;
|
||||
}
|
||||
|
||||
DateTimeFormatter getTimeFormatter() {
|
||||
@Nullable DateTimeFormatter getTimeFormatter() {
|
||||
return this.timeFormatter;
|
||||
}
|
||||
|
||||
DateTimeFormatter getDateTimeFormatter() {
|
||||
@Nullable DateTimeFormatter getDateTimeFormatter() {
|
||||
return this.dateTimeFormatter;
|
||||
}
|
||||
|
||||
@@ -97,7 +99,7 @@ public class DateTimeFormatters {
|
||||
return this.dateFormatter != null || this.timeFormatter != null || this.dateTimeFormatter != null;
|
||||
}
|
||||
|
||||
private static DateTimeFormatter formatter(String pattern) {
|
||||
private static @Nullable DateTimeFormatter formatter(String pattern) {
|
||||
return StringUtils.hasText(pattern)
|
||||
? DateTimeFormatter.ofPattern(pattern).withResolverStyle(ResolverStyle.SMART) : null;
|
||||
}
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
import org.springframework.format.datetime.DateFormatterRegistrar;
|
||||
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
|
||||
@@ -79,7 +81,7 @@ public class WebConversionService extends DefaultFormattingConversionService {
|
||||
dateTime.registerFormatters(this);
|
||||
}
|
||||
|
||||
private void configure(Supplier<DateTimeFormatter> supplier, Consumer<DateTimeFormatter> consumer) {
|
||||
private void configure(Supplier<@Nullable DateTimeFormatter> supplier, Consumer<DateTimeFormatter> consumer) {
|
||||
DateTimeFormatter formatter = supplier.get();
|
||||
if (formatter != null) {
|
||||
consumer.accept(formatter);
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Support classes for web-specific formatting.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.web.format;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for common web concerns.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ class TemplateAvailabilityProvidersTests {
|
||||
void createWhenApplicationContextIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new TemplateAvailabilityProviders((ApplicationContext) null))
|
||||
.withMessageContaining("'classLoader' must not be null");
|
||||
.withMessageContaining("'applicationContext' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user