diff --git a/config/checkstyle/checkstyle-suppressions.xml b/config/checkstyle/checkstyle-suppressions.xml
index 9dab7d74a1b..04064bd8a80 100644
--- a/config/checkstyle/checkstyle-suppressions.xml
+++ b/config/checkstyle/checkstyle-suppressions.xml
@@ -86,4 +86,8 @@
+
+
+
+
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationArguments.java b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationArguments.java
index e18c7f04afa..821a5b4cc48 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationArguments.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationArguments.java
@@ -19,6 +19,8 @@ package org.springframework.boot;
import java.util.List;
import java.util.Set;
+import org.jspecify.annotations.Nullable;
+
/**
* Provides access to the arguments that were used to run a {@link SpringApplication}.
*
@@ -63,7 +65,7 @@ public interface ApplicationArguments {
* @param name the name of the option
* @return a list of option values for the given name
*/
- List getOptionValues(String name);
+ @Nullable List getOptionValues(String name);
/**
* Return the collection of non-option arguments parsed.
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java
index 8b5afca8755..f18a7a6022d 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.beans.BeanUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -46,11 +48,12 @@ public interface ApplicationContextFactory {
* Return the {@link Environment} type expected to be set on the
* {@link #create(WebApplicationType) created} application context. The result of this
* method can be used to convert an existing environment instance to the correct type.
- * @param webApplicationType the web application type
+ * @param webApplicationType the web application type or {@code null}
* @return the expected application context type or {@code null} to use the default
* @since 2.6.14
*/
- default Class extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
+ default @Nullable Class extends ConfigurableEnvironment> getEnvironmentType(
+ @Nullable WebApplicationType webApplicationType) {
return null;
}
@@ -59,11 +62,11 @@ public interface ApplicationContextFactory {
* {@link #create(WebApplicationType) created} application context. The result of this
* method must match the type returned by
* {@link #getEnvironmentType(WebApplicationType)}.
- * @param webApplicationType the web application type
+ * @param webApplicationType the web application type or {@code null}
* @return an environment instance or {@code null} to use the default
* @since 2.6.14
*/
- default ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
+ default @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {
return null;
}
@@ -73,7 +76,7 @@ public interface ApplicationContextFactory {
* @param webApplicationType the web application type
* @return the newly created application context
*/
- ConfigurableApplicationContext create(WebApplicationType webApplicationType);
+ ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType);
/**
* Creates an {@code ApplicationContextFactory} that will create contexts by
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationEnvironment.java b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationEnvironment.java
index 39ef60fd1e0..79bc85f2a25 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationEnvironment.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationEnvironment.java
@@ -16,6 +16,8 @@
package org.springframework.boot;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.core.env.ConfigurablePropertyResolver;
import org.springframework.core.env.MutablePropertySources;
@@ -29,12 +31,12 @@ import org.springframework.core.env.StandardEnvironment;
class ApplicationEnvironment extends StandardEnvironment {
@Override
- protected String doGetActiveProfilesProperty() {
+ protected @Nullable String doGetActiveProfilesProperty() {
return null;
}
@Override
- protected String doGetDefaultProfilesProperty() {
+ protected @Nullable String doGetDefaultProfilesProperty() {
return null;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationInfoPropertySource.java b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationInfoPropertySource.java
index 3e39d416ad9..95c0d797546 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationInfoPropertySource.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationInfoPropertySource.java
@@ -19,6 +19,8 @@ package org.springframework.boot;
import java.util.HashMap;
import java.util.Map;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.system.ApplicationPid;
@@ -38,7 +40,7 @@ class ApplicationInfoPropertySource extends MapPropertySource implements OriginL
static final String NAME = "applicationInfo";
- ApplicationInfoPropertySource(Class> mainClass) {
+ ApplicationInfoPropertySource(@Nullable Class> mainClass) {
super(NAME, getProperties(readVersion(mainClass)));
}
@@ -47,7 +49,7 @@ class ApplicationInfoPropertySource extends MapPropertySource implements OriginL
}
@Override
- public Origin getOrigin(String key) {
+ public @Nullable Origin getOrigin(String key) {
return null;
}
@@ -56,7 +58,7 @@ class ApplicationInfoPropertySource extends MapPropertySource implements OriginL
return true;
}
- private static Map getProperties(String applicationVersion) {
+ private static Map getProperties(@Nullable String applicationVersion) {
Map result = new HashMap<>();
if (StringUtils.hasText(applicationVersion)) {
result.put("spring.application.version", applicationVersion);
@@ -68,7 +70,7 @@ class ApplicationInfoPropertySource extends MapPropertySource implements OriginL
return result;
}
- private static String readVersion(Class> applicationClass) {
+ private static @Nullable String readVersion(@Nullable Class> applicationClass) {
Package sourcePackage = (applicationClass != null) ? applicationClass.getPackage() : null;
return (sourcePackage != null) ? sourcePackage.getImplementationVersion() : null;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationProperties.java b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationProperties.java
index 1811e67424e..48058b7d6bb 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ApplicationProperties.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ApplicationProperties.java
@@ -19,12 +19,15 @@ package org.springframework.boot;
import java.util.LinkedHashSet;
import java.util.Set;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;
import org.springframework.boot.logging.LoggingSystemProperty;
import org.springframework.core.env.Environment;
+import org.springframework.util.Assert;
/**
* Spring application properties.
@@ -48,7 +51,7 @@ class ApplicationProperties {
/**
* Mode used to display the banner when the application runs.
*/
- private Banner.Mode bannerMode;
+ private Banner.@Nullable Mode bannerMode;
/**
* Whether to keep the application alive even if there are no more non-daemon threads.
@@ -80,7 +83,7 @@ class ApplicationProperties {
* Flag to explicitly request a specific type of web application. If not set,
* auto-detected based on the classpath.
*/
- private WebApplicationType webApplicationType;
+ private @Nullable WebApplicationType webApplicationType;
boolean isAllowBeanDefinitionOverriding() {
return this.allowBeanDefinitionOverriding;
@@ -102,12 +105,13 @@ class ApplicationProperties {
if (this.bannerMode != null) {
return this.bannerMode;
}
- boolean structuredLoggingEnabled = environment
- .containsProperty(LoggingSystemProperty.CONSOLE_STRUCTURED_FORMAT.getApplicationPropertyName());
+ String applicationPropertyName = LoggingSystemProperty.CONSOLE_STRUCTURED_FORMAT.getApplicationPropertyName();
+ Assert.state(applicationPropertyName != null, "applicationPropertyName must not be null");
+ boolean structuredLoggingEnabled = environment.containsProperty(applicationPropertyName);
return (structuredLoggingEnabled) ? Mode.OFF : Banner.Mode.CONSOLE;
}
- void setBannerMode(Mode bannerMode) {
+ void setBannerMode(@Nullable Mode bannerMode) {
this.bannerMode = bannerMode;
}
@@ -151,18 +155,18 @@ class ApplicationProperties {
this.sources = new LinkedHashSet<>(sources);
}
- WebApplicationType getWebApplicationType() {
+ @Nullable WebApplicationType getWebApplicationType() {
return this.webApplicationType;
}
- void setWebApplicationType(WebApplicationType webApplicationType) {
+ void setWebApplicationType(@Nullable WebApplicationType webApplicationType) {
this.webApplicationType = webApplicationType;
}
static class ApplicationPropertiesRuntimeHints implements RuntimeHintsRegistrar {
@Override
- public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+ public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
BindableRuntimeHintsRegistrar.forTypes(ApplicationProperties.class).registerHints(hints, classLoader);
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/Banner.java b/core/spring-boot/src/main/java/org/springframework/boot/Banner.java
index 2cc278a9c3e..4aa6b5ec069 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/Banner.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/Banner.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.io.PrintStream;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.core.env.Environment;
/**
@@ -34,10 +36,10 @@ public interface Banner {
/**
* Print the banner to the specified print stream.
* @param environment the spring environment
- * @param sourceClass the source class for the application
+ * @param sourceClass the source class for the application or {@code null}
* @param out the output print stream
*/
- void printBanner(Environment environment, Class> sourceClass, PrintStream out);
+ void printBanner(Environment environment, @Nullable Class> sourceClass, PrintStream out);
/**
* An enumeration of possible values for configuring the Banner.
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java b/core/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java
index 2f04ad91fe5..e0519799dff 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java
@@ -23,6 +23,7 @@ import java.util.Set;
import java.util.regex.Pattern;
import groovy.lang.Closure;
+import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -68,11 +69,11 @@ class BeanDefinitionLoader {
private final AbstractBeanDefinitionReader xmlReader;
- private final BeanDefinitionReader groovyReader;
+ private final @Nullable BeanDefinitionReader groovyReader;
private final ClassPathBeanDefinitionScanner scanner;
- private ResourceLoader resourceLoader;
+ private @Nullable ResourceLoader resourceLoader;
/**
* Create a new {@link BeanDefinitionLoader} that will load beans into the specified
@@ -86,7 +87,7 @@ class BeanDefinitionLoader {
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
- this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
+ this.groovyReader = isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null;
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
@@ -152,7 +153,7 @@ class BeanDefinitionLoader {
}
private void load(Class> source) {
- if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
+ if (this.groovyReader != null && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
@@ -163,7 +164,9 @@ class BeanDefinitionLoader {
}
private void load(Resource source) {
- if (source.getFilename().endsWith(".groovy")) {
+ String filename = source.getFilename();
+ Assert.state(filename != null, "Source has no filename");
+ if (filename.endsWith(".groovy")) {
if (this.groovyReader == null) {
throw new BeanDefinitionStoreException("Cannot load Groovy beans without Groovy on classpath");
}
@@ -231,7 +234,7 @@ class BeanDefinitionLoader {
}
}
- private boolean isLoadCandidate(Resource resource) {
+ private boolean isLoadCandidate(@Nullable Resource resource) {
if (resource == null || !resource.exists()) {
return false;
}
@@ -253,7 +256,7 @@ class BeanDefinitionLoader {
return true;
}
- private Package findPackage(CharSequence source) {
+ private @Nullable Package findPackage(CharSequence source) {
Package pkg = getClass().getClassLoader().getDefinedPackage(source.toString());
if (pkg != null) {
return pkg;
@@ -264,7 +267,9 @@ class BeanDefinitionLoader {
Resource[] resources = resolver
.getResources(ClassUtils.convertClassNameToResourcePath(source.toString()) + "/*.class");
for (Resource resource : resources) {
- String className = StringUtils.stripFilenameExtension(resource.getFilename());
+ String filename = resource.getFilename();
+ Assert.state(filename != null, "No filename available");
+ String className = StringUtils.stripFilenameExtension(filename);
load(Class.forName(source + "." + className));
break;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/BootstrapContext.java b/core/spring-boot/src/main/java/org/springframework/boot/BootstrapContext.java
index 3abc682e543..bd3678106e5 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/BootstrapContext.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/BootstrapContext.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
@@ -41,7 +43,7 @@ public interface BootstrapContext {
* @return the instance managed by the context
* @throws IllegalStateException if the type has not been registered
*/
- T get(Class type) throws IllegalStateException;
+ @Nullable T get(Class type) throws IllegalStateException;
/**
* Return an instance from the context if the type has been registered. The instance
@@ -51,7 +53,7 @@ public interface BootstrapContext {
* @param other the instance to use if the type has not been registered
* @return the instance
*/
- T getOrElse(Class type, T other);
+ @Nullable T getOrElse(Class type, @Nullable T other);
/**
* Return an instance from the context if the type has been registered. The instance
@@ -61,7 +63,7 @@ public interface BootstrapContext {
* @param other a supplier for the instance to use if the type has not been registered
* @return the instance
*/
- T getOrElseSupply(Class type, Supplier other);
+ @Nullable T getOrElseSupply(Class type, Supplier<@Nullable T> other);
/**
* Return an instance from the context if the type has been registered. The instance
@@ -74,7 +76,8 @@ public interface BootstrapContext {
* @throws X if the type has not been registered
* @throws IllegalStateException if the type has not been registered
*/
- T getOrElseThrow(Class type, Supplier extends X> exceptionSupplier) throws X;
+ @Nullable T getOrElseThrow(Class type, Supplier extends X> exceptionSupplier)
+ throws X;
/**
* Return if a registration exists for the given type.
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/BootstrapRegistry.java b/core/spring-boot/src/main/java/org/springframework/boot/BootstrapRegistry.java
index 35f49ad3f0d..30c5c5f8f46 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/BootstrapRegistry.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/BootstrapRegistry.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;
@@ -78,7 +80,7 @@ public interface BootstrapRegistry {
* @param type the instance type
* @return the registered {@link InstanceSupplier} or {@code null}
*/
- InstanceSupplier getRegisteredInstanceSupplier(Class type);
+ @Nullable InstanceSupplier getRegisteredInstanceSupplier(Class type);
/**
* Add an {@link ApplicationListener} that will be called with a
@@ -101,9 +103,9 @@ public interface BootstrapRegistry {
* Factory method used to create the instance when needed.
* @param context the {@link BootstrapContext} which may be used to obtain other
* bootstrap instances.
- * @return the instance
+ * @return the instance or {@code null}
*/
- T get(BootstrapContext context);
+ @Nullable T get(BootstrapContext context);
/**
* Return the scope of the supplied instance.
@@ -126,7 +128,7 @@ public interface BootstrapRegistry {
return new InstanceSupplier<>() {
@Override
- public T get(BootstrapContext context) {
+ public @Nullable T get(BootstrapContext context) {
return parent.get(context);
}
@@ -145,7 +147,7 @@ public interface BootstrapRegistry {
* @param instance the instance
* @return a new {@link InstanceSupplier}
*/
- static InstanceSupplier of(T instance) {
+ static InstanceSupplier of(@Nullable T instance) {
return (registry) -> instance;
}
@@ -156,7 +158,7 @@ public interface BootstrapRegistry {
* @param supplier the supplier that will provide the instance
* @return a new {@link InstanceSupplier}
*/
- static InstanceSupplier from(Supplier supplier) {
+ static InstanceSupplier from(@Nullable Supplier supplier) {
return (registry) -> (supplier != null) ? supplier.get() : null;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ClearCachesApplicationListener.java b/core/spring-boot/src/main/java/org/springframework/boot/ClearCachesApplicationListener.java
index 5740b043256..9ef9e06073d 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ClearCachesApplicationListener.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ClearCachesApplicationListener.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.lang.reflect.Method;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.util.ReflectionUtils;
@@ -35,7 +37,7 @@ class ClearCachesApplicationListener implements ApplicationListener getOptionValues(String name) {
+ public @Nullable List getOptionValues(String name) {
List values = this.source.getOptionValues(name);
return (values != null) ? Collections.unmodifiableList(values) : null;
}
@@ -82,7 +84,7 @@ public class DefaultApplicationArguments implements ApplicationArguments {
}
@Override
- public List getOptionValues(String name) {
+ public @Nullable List getOptionValues(String name) {
return super.getOptionValues(name);
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationContextFactory.java b/core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationContextFactory.java
index 5bfc15362fc..4e9f24f5ab4 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationContextFactory.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationContextFactory.java
@@ -19,12 +19,15 @@ package org.springframework.boot;
import java.util.function.BiFunction;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.aot.AotDetector;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
+import org.springframework.lang.Contract;
/**
* Default {@link ApplicationContextFactory} implementation that will create an
@@ -34,18 +37,25 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
*/
class DefaultApplicationContextFactory implements ApplicationContextFactory {
+ // Method reference is not detected with correct nullability
+ @SuppressWarnings("NullAway")
@Override
- public Class extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
+ public @Nullable Class extends ConfigurableEnvironment> getEnvironmentType(
+ @Nullable WebApplicationType webApplicationType) {
return getFromSpringFactories(webApplicationType, ApplicationContextFactory::getEnvironmentType, null);
}
+ // Method reference is not detected with correct nullability
+ @SuppressWarnings("NullAway")
@Override
- public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
+ public @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {
return getFromSpringFactories(webApplicationType, ApplicationContextFactory::createEnvironment, null);
}
+ // Method reference is not detected with correct nullability
+ @SuppressWarnings("NullAway")
@Override
- public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
+ public ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) {
try {
return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
this::createDefaultApplicationContext);
@@ -63,8 +73,10 @@ class DefaultApplicationContextFactory implements ApplicationContextFactory {
return new GenericApplicationContext();
}
- private T getFromSpringFactories(WebApplicationType webApplicationType,
- BiFunction action, Supplier defaultResult) {
+ @Contract("_, _, !null -> !null")
+ private @Nullable T getFromSpringFactories(@Nullable WebApplicationType webApplicationType,
+ BiFunction action,
+ @Nullable Supplier defaultResult) {
for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
getClass().getClassLoader())) {
T result = action.apply(candidate, webApplicationType);
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/DefaultBootstrapContext.java b/core/spring-boot/src/main/java/org/springframework/boot/DefaultBootstrapContext.java
index 05faf209a40..063aff688b4 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/DefaultBootstrapContext.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/DefaultBootstrapContext.java
@@ -20,6 +20,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
@@ -72,7 +74,7 @@ public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
@Override
@SuppressWarnings("unchecked")
- public InstanceSupplier getRegisteredInstanceSupplier(Class type) {
+ public @Nullable InstanceSupplier getRegisteredInstanceSupplier(Class type) {
synchronized (this.instanceSuppliers) {
return (InstanceSupplier) this.instanceSuppliers.get(type);
}
@@ -84,17 +86,18 @@ public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
}
@Override
- public T get(Class type) throws IllegalStateException {
+ public @Nullable T get(Class type) throws IllegalStateException {
return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered"));
}
@Override
- public T getOrElse(Class type, T other) {
+ @SuppressWarnings("NullAway") // Doesn't detect lambda with correct nullability
+ public @Nullable T getOrElse(Class type, @Nullable T other) {
return getOrElseSupply(type, () -> other);
}
@Override
- public T getOrElseSupply(Class type, Supplier other) {
+ public @Nullable T getOrElseSupply(Class type, Supplier<@Nullable T> other) {
synchronized (this.instanceSuppliers) {
InstanceSupplier> instanceSupplier = this.instanceSuppliers.get(type);
return (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();
@@ -102,7 +105,8 @@ public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
}
@Override
- public T getOrElseThrow(Class type, Supplier extends X> exceptionSupplier) throws X {
+ public @Nullable T getOrElseThrow(Class type, Supplier extends X> exceptionSupplier)
+ throws X {
synchronized (this.instanceSuppliers) {
InstanceSupplier> instanceSupplier = this.instanceSuppliers.get(type);
if (instanceSupplier == null) {
@@ -113,10 +117,13 @@ public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
}
@SuppressWarnings("unchecked")
- private T getInstance(Class type, InstanceSupplier> instanceSupplier) {
+ private @Nullable T getInstance(Class type, InstanceSupplier> instanceSupplier) {
T instance = (T) this.instances.get(type);
if (instance == null) {
instance = (T) instanceSupplier.get(this);
+ if (instance == null) {
+ return null;
+ }
if (instanceSupplier.getScope() == Scope.SINGLETON) {
this.instances.put(type, instance);
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/DefaultPropertiesPropertySource.java b/core/spring-boot/src/main/java/org/springframework/boot/DefaultPropertiesPropertySource.java
index 7e1eef02fea..ee19df5bfa5 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/DefaultPropertiesPropertySource.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/DefaultPropertiesPropertySource.java
@@ -20,6 +20,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
@@ -56,7 +58,7 @@ public class DefaultPropertiesPropertySource extends MapPropertySource {
* @param propertySource the property source to check
* @return {@code true} if the name matches
*/
- public static boolean hasMatchingName(PropertySource> propertySource) {
+ public static boolean hasMatchingName(@Nullable PropertySource> propertySource) {
return (propertySource != null) && propertySource.getName().equals(NAME);
}
@@ -67,7 +69,8 @@ public class DefaultPropertiesPropertySource extends MapPropertySource {
* @param action the action used to consume the
* {@link DefaultPropertiesPropertySource}
*/
- public static void ifNotEmpty(Map source, Consumer action) {
+ public static void ifNotEmpty(Map source,
+ @Nullable Consumer action) {
if (!CollectionUtils.isEmpty(source) && action != null) {
action.accept(new DefaultPropertiesPropertySource(source));
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java b/core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java
index a982c5fb579..6e6df421d1e 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java
@@ -19,6 +19,8 @@ package org.springframework.boot;
import java.util.ArrayList;
import java.util.Collection;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
@@ -84,7 +86,7 @@ public final class LazyInitializationBeanFactoryPostProcessor implements BeanFac
}
}
- private Class> getBeanType(ConfigurableListableBeanFactory beanFactory, String beanName) {
+ private @Nullable Class> getBeanType(ConfigurableListableBeanFactory beanFactory, String beanName) {
try {
return beanFactory.getType(beanName, false);
}
@@ -94,7 +96,7 @@ public final class LazyInitializationBeanFactoryPostProcessor implements BeanFac
}
private boolean isExcluded(Collection filters, String beanName,
- AbstractBeanDefinition beanDefinition, Class> beanType) {
+ AbstractBeanDefinition beanDefinition, @Nullable Class> beanType) {
if (beanType != null) {
for (LazyInitializationExcludeFilter filter : filters) {
if (filter.isExcluded(beanName, beanDefinition, beanType)) {
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java b/core/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java
index 8e6f1a5ee35..f5ae815b4ee 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java
@@ -28,6 +28,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.jspecify.annotations.Nullable;
import org.springframework.boot.ansi.AnsiPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -64,7 +65,7 @@ public class ResourceBanner implements Banner {
}
@Override
- public void printBanner(Environment environment, Class> sourceClass, PrintStream out) {
+ public void printBanner(Environment environment, @Nullable Class> sourceClass, PrintStream out) {
try (InputStream input = this.resource.getInputStream()) {
String banner = StreamUtils.copyToString(input,
environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8));
@@ -86,32 +87,32 @@ public class ResourceBanner implements Banner {
* @param sourceClass the source class
* @return a mutable list of property resolvers
*/
- protected List getPropertyResolvers(Environment environment, Class> sourceClass) {
+ protected List getPropertyResolvers(Environment environment, @Nullable Class> sourceClass) {
List resolvers = new ArrayList<>();
resolvers.add(new PropertySourcesPropertyResolver(createNullDefaultSources(environment, sourceClass)));
resolvers.add(new PropertySourcesPropertyResolver(createEmptyDefaultSources(environment, sourceClass)));
return resolvers;
}
- private MutablePropertySources createNullDefaultSources(Environment environment, Class> sourceClass) {
+ private MutablePropertySources createNullDefaultSources(Environment environment, @Nullable Class> sourceClass) {
MutablePropertySources nullDefaultSources = new MutablePropertySources();
if (environment instanceof ConfigurableEnvironment configurableEnvironment) {
configurableEnvironment.getPropertySources().forEach(nullDefaultSources::addLast);
}
nullDefaultSources.addLast(getTitleSource(sourceClass, null));
nullDefaultSources.addLast(getAnsiSource());
- nullDefaultSources.addLast(getVersionSource(sourceClass, environment, null));
+ nullDefaultSources.addLast(getVersionSource(environment, null));
return nullDefaultSources;
}
- private MutablePropertySources createEmptyDefaultSources(Environment environment, Class> sourceClass) {
+ private MutablePropertySources createEmptyDefaultSources(Environment environment, @Nullable Class> sourceClass) {
MutablePropertySources emptyDefaultSources = new MutablePropertySources();
emptyDefaultSources.addLast(getTitleSource(sourceClass, ""));
- emptyDefaultSources.addLast(getVersionSource(sourceClass, environment, ""));
+ emptyDefaultSources.addLast(getVersionSource(environment, ""));
return emptyDefaultSources;
}
- private MapPropertySource getTitleSource(Class> sourceClass, String defaultValue) {
+ private MapPropertySource getTitleSource(@Nullable Class> sourceClass, @Nullable String defaultValue) {
String applicationTitle = getApplicationTitle(sourceClass);
Map titleMap = Collections.singletonMap("application.title",
(applicationTitle != null) ? applicationTitle : defaultValue);
@@ -124,7 +125,7 @@ public class ResourceBanner implements Banner {
* @param sourceClass the source class
* @return the application title
*/
- protected String getApplicationTitle(Class> sourceClass) {
+ protected @Nullable String getApplicationTitle(@Nullable Class> sourceClass) {
Package sourcePackage = (sourceClass != null) ? sourceClass.getPackage() : null;
return (sourcePackage != null) ? sourcePackage.getImplementationTitle() : null;
}
@@ -133,11 +134,11 @@ public class ResourceBanner implements Banner {
return new AnsiPropertySource("ansi", true);
}
- private MapPropertySource getVersionSource(Class> sourceClass, Environment environment, String defaultValue) {
- return new MapPropertySource("version", getVersionsMap(sourceClass, environment, defaultValue));
+ private MapPropertySource getVersionSource(Environment environment, @Nullable String defaultValue) {
+ return new MapPropertySource("version", getVersionsMap(environment, defaultValue));
}
- private Map getVersionsMap(Class> sourceClass, Environment environment, String defaultValue) {
+ private Map getVersionsMap(Environment environment, @Nullable String defaultValue) {
String appVersion = getApplicationVersion(environment);
String bootVersion = getBootVersion();
Map versions = new HashMap<>();
@@ -148,7 +149,7 @@ public class ResourceBanner implements Banner {
return versions;
}
- private String getApplicationVersion(Environment environment) {
+ private @Nullable String getApplicationVersion(Environment environment) {
return environment.getProperty("spring.application.version");
}
@@ -156,7 +157,7 @@ public class ResourceBanner implements Banner {
return SpringBootVersion.getVersion();
}
- private String getVersionString(String version, boolean format, String fallback) {
+ private @Nullable String getVersionString(@Nullable String version, boolean format, @Nullable String fallback) {
if (version == null) {
return fallback;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
index 51ece877060..0e3078fe32f 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
@@ -41,6 +41,7 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.crac.management.CRaCMXBean;
+import org.jspecify.annotations.Nullable;
import org.springframework.aot.AotDetector;
import org.springframework.beans.BeansException;
@@ -204,27 +205,27 @@ public class SpringApplication {
private final Set> primarySources;
- private Class> mainApplicationClass;
+ private @Nullable Class> mainApplicationClass;
private boolean addCommandLineProperties = true;
private boolean addConversionService = true;
- private Banner banner;
+ private @Nullable Banner banner;
- private ResourceLoader resourceLoader;
+ private @Nullable ResourceLoader resourceLoader;
- private BeanNameGenerator beanNameGenerator;
+ private @Nullable BeanNameGenerator beanNameGenerator;
- private ConfigurableEnvironment environment;
+ private @Nullable ConfigurableEnvironment environment;
private boolean headless = true;
- private List> initializers;
+ private List> initializers = new ArrayList<>();
- private List> listeners;
+ private List> listeners = new ArrayList<>();
- private Map defaultProperties;
+ private @Nullable Map defaultProperties;
private final List bootstrapRegistryInitializers;
@@ -232,7 +233,7 @@ public class SpringApplication {
private boolean isCustomEnvironment;
- private String environmentPrefix;
+ private @Nullable String environmentPrefix;
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;
@@ -265,7 +266,7 @@ public class SpringApplication {
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
- public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
+ public SpringApplication(@Nullable ResourceLoader resourceLoader, Class>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "'primarySources' must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
@@ -277,7 +278,7 @@ public class SpringApplication {
this.mainApplicationClass = deduceMainApplicationClass();
}
- private Class> deduceMainApplicationClass() {
+ private @Nullable Class> deduceMainApplicationClass() {
return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk(this::findMainClass)
.orElse(null);
@@ -314,11 +315,11 @@ public class SpringApplication {
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
- startup.started();
+ Duration timeTakenToStarted = startup.started();
if (this.properties.isLogStartupInfo()) {
new StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup);
}
- listeners.started(context, startup.timeTakenToStarted());
+ listeners.started(context, timeTakenToStarted);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
@@ -373,7 +374,7 @@ public class SpringApplication {
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
- ApplicationArguments applicationArguments, Banner printedBanner) {
+ ApplicationArguments applicationArguments, @Nullable Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
addAotGeneratedInitializerIfNecessary(this.initializers);
@@ -417,6 +418,7 @@ public class SpringApplication {
List> aotInitializers = new ArrayList<>(
initializers.stream().filter(AotApplicationContextInitializer.class::isInstance).toList());
if (aotInitializers.isEmpty()) {
+ Assert.state(this.mainApplicationClass != null, "No application main class found");
String initializerClassName = this.mainApplicationClass.getName() + "__ApplicationContextInitializer";
if (!ClassUtils.isPresent(initializerClassName, getClassLoader())) {
throw new AotInitializerNotFoundException(this.mainApplicationClass, initializerClassName);
@@ -458,7 +460,7 @@ public class SpringApplication {
return getSpringFactoriesInstances(type, null);
}
- private List getSpringFactoriesInstances(Class type, ArgumentResolver argumentResolver) {
+ private List getSpringFactoriesInstances(Class type, @Nullable ArgumentResolver argumentResolver) {
return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
}
@@ -507,8 +509,8 @@ public class SpringApplication {
}
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
- if (sources.contains(name)) {
- PropertySource> source = sources.get(name);
+ PropertySource> source = sources.get(name);
+ if (source != null) {
CompositePropertySource composite = new CompositePropertySource(name);
composite
.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
@@ -546,7 +548,7 @@ public class SpringApplication {
}
}
- private Banner printBanner(ConfigurableEnvironment environment) {
+ private @Nullable Banner printBanner(ConfigurableEnvironment environment) {
if (this.properties.getBannerMode(environment) == Banner.Mode.OFF) {
return null;
}
@@ -604,6 +606,8 @@ public class SpringApplication {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
+ Assert.state(requiredType != null,
+ () -> "No generic type found for initializr of type " + initializer.getClass());
Assert.state(requiredType.isInstance(context), "Unable to call initializer");
initializer.initialize(context);
}
@@ -685,9 +689,9 @@ public class SpringApplication {
/**
* The ResourceLoader that will be used in the ApplicationContext.
* @return the resourceLoader the resource loader that will be used in the
- * ApplicationContext (or null if the default)
+ * ApplicationContext (or {@code null} if the default)
*/
- public ResourceLoader getResourceLoader() {
+ public @Nullable ResourceLoader getResourceLoader() {
return this.resourceLoader;
}
@@ -699,9 +703,13 @@ public class SpringApplication {
*/
public ClassLoader getClassLoader() {
if (this.resourceLoader != null) {
- return this.resourceLoader.getClassLoader();
+ ClassLoader classLoader = this.resourceLoader.getClassLoader();
+ Assert.state(classLoader != null, "No classloader found");
+ return classLoader;
}
- return ClassUtils.getDefaultClassLoader();
+ ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
+ Assert.state(classLoader != null, "No classloader found");
+ return classLoader;
}
/**
@@ -781,8 +789,8 @@ public class SpringApplication {
.accept((R) runner);
}
- private RuntimeException handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
- SpringApplicationRunListeners listeners) {
+ private RuntimeException handleRunFailure(@Nullable ConfigurableApplicationContext context, Throwable exception,
+ @Nullable SpringApplicationRunListeners listeners) {
if (exception instanceof AbandonedRunException abandonedRunException) {
return abandonedRunException;
}
@@ -808,9 +816,11 @@ public class SpringApplication {
: new IllegalStateException(exception);
}
- private Collection getExceptionReporters(ConfigurableApplicationContext context) {
+ private Collection getExceptionReporters(
+ @Nullable ConfigurableApplicationContext context) {
try {
- ArgumentResolver argumentResolver = ArgumentResolver.of(ConfigurableApplicationContext.class, context);
+ ArgumentResolver argumentResolver = (context != null)
+ ? ArgumentResolver.of(ConfigurableApplicationContext.class, context) : ArgumentResolver.none();
return getSpringFactoriesInstances(SpringBootExceptionReporter.class, argumentResolver);
}
catch (Throwable ex) {
@@ -857,7 +867,7 @@ public class SpringApplication {
}
}
- private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) {
+ private void handleExitCode(@Nullable ConfigurableApplicationContext context, Throwable exception) {
int exitCode = getExitCodeFromException(context, exception);
if (exitCode != 0) {
if (context != null) {
@@ -870,7 +880,7 @@ public class SpringApplication {
}
}
- private int getExitCodeFromException(ConfigurableApplicationContext context, Throwable exception) {
+ private int getExitCodeFromException(@Nullable ConfigurableApplicationContext context, Throwable exception) {
int exitCode = getExitCodeFromMappedException(context, exception);
if (exitCode == 0) {
exitCode = getExitCodeFromExitCodeGeneratorException(exception);
@@ -878,7 +888,7 @@ public class SpringApplication {
return exitCode;
}
- private int getExitCodeFromMappedException(ConfigurableApplicationContext context, Throwable exception) {
+ private int getExitCodeFromMappedException(@Nullable ConfigurableApplicationContext context, Throwable exception) {
if (context == null || !context.isActive()) {
return 0;
}
@@ -888,7 +898,7 @@ public class SpringApplication {
return generators.getExitCode();
}
- private int getExitCodeFromExitCodeGeneratorException(Throwable exception) {
+ private int getExitCodeFromExitCodeGeneratorException(@Nullable Throwable exception) {
if (exception == null) {
return 0;
}
@@ -898,7 +908,7 @@ public class SpringApplication {
return getExitCodeFromExitCodeGeneratorException(exception.getCause());
}
- SpringBootExceptionHandler getSpringBootExceptionHandler() {
+ @Nullable SpringBootExceptionHandler getSpringBootExceptionHandler() {
if (isMainThread(Thread.currentThread())) {
return SpringBootExceptionHandler.forCurrentThread();
}
@@ -914,7 +924,7 @@ public class SpringApplication {
* Returns the main application class that has been deduced or explicitly configured.
* @return the main application class or {@code null}
*/
- public Class> getMainApplicationClass() {
+ public @Nullable Class> getMainApplicationClass() {
return this.mainApplicationClass;
}
@@ -924,7 +934,7 @@ public class SpringApplication {
* Can be set to {@code null} if there is no explicit application class.
* @param mainApplicationClass the mainApplicationClass to set or {@code null}
*/
- public void setMainApplicationClass(Class> mainApplicationClass) {
+ public void setMainApplicationClass(@Nullable Class> mainApplicationClass) {
this.mainApplicationClass = mainApplicationClass;
}
@@ -933,7 +943,7 @@ public class SpringApplication {
* @return the type of web application
* @since 2.0.0
*/
- public WebApplicationType getWebApplicationType() {
+ public @Nullable WebApplicationType getWebApplicationType() {
return this.properties.getWebApplicationType();
}
@@ -1107,7 +1117,7 @@ public class SpringApplication {
* context.
* @param environment the environment
*/
- public void setEnvironment(ConfigurableEnvironment environment) {
+ public void setEnvironment(@Nullable ConfigurableEnvironment environment) {
this.isCustomEnvironment = true;
this.environment = environment;
}
@@ -1191,7 +1201,7 @@ public class SpringApplication {
* @return the environment property prefix
* @since 2.5.0
*/
- public String getEnvironmentPrefix() {
+ public @Nullable String getEnvironmentPrefix() {
return this.environmentPrefix;
}
@@ -1213,7 +1223,7 @@ public class SpringApplication {
* @param applicationContextFactory the factory for the context
* @since 2.4.0
*/
- public void setApplicationContextFactory(ApplicationContextFactory applicationContextFactory) {
+ public void setApplicationContextFactory(@Nullable ApplicationContextFactory applicationContextFactory) {
this.applicationContextFactory = (applicationContextFactory != null) ? applicationContextFactory
: ApplicationContextFactory.DEFAULT;
}
@@ -1424,7 +1434,7 @@ public class SpringApplication {
public static void withHook(SpringApplicationHook hook, Runnable action) {
withHook(hook, () -> {
action.run();
- return null;
+ return Void.class;
});
}
@@ -1598,7 +1608,7 @@ public class SpringApplication {
*/
public static class AbandonedRunException extends RuntimeException {
- private final ConfigurableApplicationContext applicationContext;
+ private final @Nullable ConfigurableApplicationContext applicationContext;
/**
* Create a new {@link AbandonedRunException} instance.
@@ -1613,7 +1623,7 @@ public class SpringApplication {
* @param applicationContext the application context that was available when the
* run was abandoned
*/
- public AbandonedRunException(ConfigurableApplicationContext applicationContext) {
+ public AbandonedRunException(@Nullable ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@@ -1622,7 +1632,7 @@ public class SpringApplication {
* {@code null} if no context was available.
* @return the application context
*/
- public ConfigurableApplicationContext getApplicationContext() {
+ public @Nullable ConfigurableApplicationContext getApplicationContext() {
return this.applicationContext;
}
@@ -1642,7 +1652,7 @@ public class SpringApplication {
}
@Override
- public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
+ public @Nullable SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
return this.used.compareAndSet(false, true) ? this.delegate.getRunListener(springApplication) : null;
}
@@ -1699,11 +1709,11 @@ public class SpringApplication {
*/
abstract static class Startup {
- private Duration timeTakenToStarted;
+ private @Nullable Duration timeTakenToStarted;
protected abstract long startTime();
- protected abstract Long processUptime();
+ protected abstract @Nullable Long processUptime();
protected abstract String action();
@@ -1714,6 +1724,8 @@ public class SpringApplication {
}
Duration timeTakenToStarted() {
+ Assert.state(this.timeTakenToStarted != null,
+ "timeTakenToStarted is not set. Make sure to call started() before this method");
return this.timeTakenToStarted;
}
@@ -1744,7 +1756,7 @@ public class SpringApplication {
}
@Override
- protected Long processUptime() {
+ protected @Nullable Long processUptime() {
try {
return ManagementFactory.getRuntimeMXBean().getUptime();
}
@@ -1794,7 +1806,7 @@ public class SpringApplication {
* {@link OrderSourceProvider} used to obtain factory method and target type order
* sources. Based on internal {@link DefaultListableBeanFactory} code.
*/
- private class FactoryAwareOrderSourceProvider implements OrderSourceProvider {
+ private static class FactoryAwareOrderSourceProvider implements OrderSourceProvider {
private final ConfigurableBeanFactory beanFactory;
@@ -1806,12 +1818,12 @@ public class SpringApplication {
}
@Override
- public Object getOrderSource(Object obj) {
+ public @Nullable Object getOrderSource(Object obj) {
String beanName = this.instancesToBeanNames.get(obj);
return (beanName != null) ? getOrderSource(beanName, obj.getClass()) : null;
}
- private Object getOrderSource(String beanName, Class> instanceType) {
+ private @Nullable Object getOrderSource(String beanName, Class> instanceType) {
try {
RootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory
.getMergedBeanDefinition(beanName);
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java
index d5b61138daf..13bdaf91e8e 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java
@@ -59,7 +59,8 @@ public class SpringApplicationAotProcessor extends ContextAotProcessor {
protected GenericApplicationContext prepareApplicationContext(Class> application) {
return new AotProcessorHook(application).run(() -> {
Method mainMethod = application.getMethod("main", String[].class);
- return ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
+ ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
+ return Void.class;
});
}
@@ -112,7 +113,7 @@ public class SpringApplicationAotProcessor extends ContextAotProcessor {
ApplicationContext context = ex.getApplicationContext();
Assert.state(context instanceof GenericApplicationContext,
() -> "AOT processing requires a GenericApplicationContext but got a "
- + context.getClass().getName());
+ + ((context != null) ? context.getClass().getName() : "null"));
return (GenericApplicationContext) context;
}
throw new IllegalStateException(
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java
index 95955234c39..4dd57a91576 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java
@@ -23,6 +23,7 @@ import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.logging.Log;
+import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -45,14 +46,14 @@ class SpringApplicationBannerPrinter {
private final ResourceLoader resourceLoader;
- private final Banner fallbackBanner;
+ private final @Nullable Banner fallbackBanner;
- SpringApplicationBannerPrinter(ResourceLoader resourceLoader, Banner fallbackBanner) {
+ SpringApplicationBannerPrinter(ResourceLoader resourceLoader, @Nullable Banner fallbackBanner) {
this.resourceLoader = resourceLoader;
this.fallbackBanner = fallbackBanner;
}
- Banner print(Environment environment, Class> sourceClass, Log logger) {
+ Banner print(Environment environment, @Nullable Class> sourceClass, Log logger) {
Banner banner = getBanner(environment);
try {
logger.info(createStringFromBanner(banner, environment, sourceClass));
@@ -63,7 +64,7 @@ class SpringApplicationBannerPrinter {
return new PrintedBanner(banner, sourceClass);
}
- Banner print(Environment environment, Class> sourceClass, PrintStream out) {
+ Banner print(Environment environment, @Nullable Class> sourceClass, PrintStream out) {
Banner banner = getBanner(environment);
banner.printBanner(environment, sourceClass, out);
return new PrintedBanner(banner, sourceClass);
@@ -80,7 +81,7 @@ class SpringApplicationBannerPrinter {
return DEFAULT_BANNER;
}
- private Banner getTextBanner(Environment environment) {
+ private @Nullable Banner getTextBanner(Environment environment) {
String location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);
Resource resource = this.resourceLoader.getResource(location);
try {
@@ -94,8 +95,8 @@ class SpringApplicationBannerPrinter {
return null;
}
- private String createStringFromBanner(Banner banner, Environment environment, Class> mainApplicationClass)
- throws UnsupportedEncodingException {
+ private String createStringFromBanner(Banner banner, Environment environment,
+ @Nullable Class> mainApplicationClass) throws UnsupportedEncodingException {
String charset = environment.getProperty("spring.banner.charset", StandardCharsets.UTF_8.name());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (PrintStream out = new PrintStream(byteArrayOutputStream, false, charset)) {
@@ -112,15 +113,15 @@ class SpringApplicationBannerPrinter {
private final Banner banner;
- private final Class> sourceClass;
+ private final @Nullable Class> sourceClass;
- PrintedBanner(Banner banner, Class> sourceClass) {
+ PrintedBanner(Banner banner, @Nullable Class> sourceClass) {
this.banner = banner;
this.sourceClass = sourceClass;
}
@Override
- public void printBanner(Environment environment, Class> sourceClass, PrintStream out) {
+ public void printBanner(Environment environment, @Nullable Class> sourceClass, PrintStream out) {
sourceClass = (sourceClass != null) ? sourceClass : this.sourceClass;
this.banner.printBanner(environment, sourceClass, out);
}
@@ -130,7 +131,7 @@ class SpringApplicationBannerPrinter {
static class SpringApplicationBannerPrinterRuntimeHints implements RuntimeHintsRegistrar {
@Override
- public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+ public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.resources().registerPattern(DEFAULT_BANNER_LOCATION);
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationHook.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationHook.java
index 33729b8ad33..32dd1c07c40 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationHook.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationHook.java
@@ -16,6 +16,8 @@
package org.springframework.boot;
+import org.jspecify.annotations.Nullable;
+
/**
* Low-level hook that can be used to attach a {@link SpringApplicationRunListener} to a
* {@link SpringApplication} in order to observe or modify its behavior. Hooks are managed
@@ -34,8 +36,8 @@ public interface SpringApplicationHook {
* Return the {@link SpringApplicationRunListener} that should be hooked into the
* given {@link SpringApplication}.
* @param springApplication the source {@link SpringApplication} instance
- * @return the {@link SpringApplicationRunListener} to attach
+ * @return the {@link SpringApplicationRunListener} to attach or {@code null}
*/
- SpringApplicationRunListener getRunListener(SpringApplication springApplication);
+ @Nullable SpringApplicationRunListener getRunListener(SpringApplication springApplication);
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java
index d34872043a1..e1bb3047f29 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.time.Duration;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -80,7 +82,7 @@ public interface SpringApplicationRunListener {
* @param timeTaken the time taken to start the application or {@code null} if unknown
* @since 2.6.0
*/
- default void started(ConfigurableApplicationContext context, Duration timeTaken) {
+ default void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
}
/**
@@ -92,7 +94,7 @@ public interface SpringApplicationRunListener {
* unknown
* @since 2.6.0
*/
- default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
+ default void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
}
/**
@@ -102,7 +104,7 @@ public interface SpringApplicationRunListener {
* @param exception the failure
* @since 2.0.0
*/
- default void failed(ConfigurableApplicationContext context, Throwable exception) {
+ default void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {
}
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java
index 92d4cbee548..0af7cb6b1c9 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java
@@ -21,6 +21,7 @@ import java.util.List;
import java.util.function.Consumer;
import org.apache.commons.logging.Log;
+import org.jspecify.annotations.Nullable;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -50,7 +51,7 @@ class SpringApplicationRunListeners {
this.applicationStartup = applicationStartup;
}
- void starting(ConfigurableBootstrapContext bootstrapContext, Class> mainApplicationClass) {
+ void starting(ConfigurableBootstrapContext bootstrapContext, @Nullable Class> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
@@ -80,16 +81,19 @@ class SpringApplicationRunListeners {
doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
}
- void failed(ConfigurableApplicationContext context, Throwable exception) {
+ void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {
doWithListeners("spring.boot.application.failed",
(listener) -> callFailedListener(listener, context, exception), (step) -> {
step.tag("exception", exception.getClass().toString());
- step.tag("message", exception.getMessage());
+ String message = exception.getMessage();
+ if (message != null) {
+ step.tag("message", message);
+ }
});
}
- private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
- Throwable exception) {
+ private void callFailedListener(SpringApplicationRunListener listener,
+ @Nullable ConfigurableApplicationContext context, Throwable exception) {
try {
listener.failed(context, exception);
}
@@ -113,7 +117,7 @@ class SpringApplicationRunListeners {
}
private void doWithListeners(String stepName, Consumer listenerAction,
- Consumer stepAction) {
+ @Nullable Consumer stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java
index 0627f9cf975..5835eadbdba 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java
@@ -18,6 +18,8 @@ package org.springframework.boot;
import java.io.PrintStream;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiStyle;
@@ -44,7 +46,7 @@ class SpringBootBanner implements Banner {
private static final int STRAP_LINE_SIZE = 42;
@Override
- public void printBanner(Environment environment, Class> sourceClass, PrintStream printStream) {
+ public void printBanner(Environment environment, @Nullable Class> sourceClass, PrintStream printStream) {
printStream.println();
printStream.println(BANNER);
String version = String.format(" (v%s)", SpringBootVersion.getVersion());
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionHandler.java b/core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionHandler.java
index 2e870065b53..06e579ad269 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionHandler.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionHandler.java
@@ -24,6 +24,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.jspecify.annotations.Nullable;
+
/**
* {@link UncaughtExceptionHandler} to suppress handling already logged exceptions and
* dealing with system exit.
@@ -42,13 +44,13 @@ class SpringBootExceptionHandler implements UncaughtExceptionHandler {
private static final LoggedExceptionHandlerThreadLocal handler = new LoggedExceptionHandlerThreadLocal();
- private final UncaughtExceptionHandler parent;
+ private final @Nullable UncaughtExceptionHandler parent;
private final List loggedExceptions = new ArrayList<>();
private int exitCode = 0;
- SpringBootExceptionHandler(UncaughtExceptionHandler parent) {
+ SpringBootExceptionHandler(@Nullable UncaughtExceptionHandler parent) {
this.parent = parent;
}
@@ -85,7 +87,10 @@ class SpringBootExceptionHandler implements UncaughtExceptionHandler {
* @param ex the source exception
* @return {@code true} if the exception contains a log configuration message
*/
- private boolean isLogConfigurationMessage(Throwable ex) {
+ private boolean isLogConfigurationMessage(@Nullable Throwable ex) {
+ if (ex == null) {
+ return false;
+ }
if (ex instanceof InvocationTargetException) {
return isLogConfigurationMessage(ex.getCause());
}
@@ -100,7 +105,10 @@ class SpringBootExceptionHandler implements UncaughtExceptionHandler {
return false;
}
- private boolean isRegistered(Throwable ex) {
+ private boolean isRegistered(@Nullable Throwable ex) {
+ if (ex == null) {
+ return false;
+ }
if (this.loggedExceptions.contains(ex)) {
return true;
}
diff --git a/core/spring-boot/src/main/java/org/springframework/boot/StartupInfoLogger.java b/core/spring-boot/src/main/java/org/springframework/boot/StartupInfoLogger.java
index 18b87c361cb..13bcf556eb2 100644
--- a/core/spring-boot/src/main/java/org/springframework/boot/StartupInfoLogger.java
+++ b/core/spring-boot/src/main/java/org/springframework/boot/StartupInfoLogger.java
@@ -19,6 +19,7 @@ package org.springframework.boot;
import java.util.concurrent.Callable;
import org.apache.commons.logging.Log;
+import org.jspecify.annotations.Nullable;
import org.springframework.aot.AotDetector;
import org.springframework.boot.SpringApplication.Startup;
@@ -39,11 +40,11 @@ import org.springframework.util.StringUtils;
*/
class StartupInfoLogger {
- private final Class> sourceClass;
+ private final @Nullable Class> sourceClass;
private final Environment environment;
- StartupInfoLogger(Class> sourceClass, Environment environment) {
+ StartupInfoLogger(@Nullable Class> sourceClass, Environment environment) {
this.sourceClass = sourceClass;
this.environment = environment;
}
@@ -153,7 +154,7 @@ class StartupInfoLogger {
}
}
- private Object callIfPossible(Callable