mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-03 15:59:31 +00:00
Improve null-safety of core/spring-boot
See gh-46926
This commit is contained in:
+4
-2
@@ -20,6 +20,8 @@ import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -50,9 +52,9 @@ class ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegist
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
private final @Nullable ResourceLoader resourceLoader;
|
||||
|
||||
ConfigurationPropertiesScanRegistrar(Environment environment, ResourceLoader resourceLoader) {
|
||||
ConfigurationPropertiesScanRegistrar(Environment environment, @Nullable ResourceLoader resourceLoader) {
|
||||
this.environment = environment;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ interface CachingConfigurationPropertySource {
|
||||
* @return a {@link ConfigurationPropertyCaching} instance or {@code null} if the
|
||||
* source does not support caching.
|
||||
*/
|
||||
static @Nullable ConfigurationPropertyCaching find(ConfigurationPropertySource source) {
|
||||
static @Nullable ConfigurationPropertyCaching find(@Nullable ConfigurationPropertySource source) {
|
||||
if (source instanceof CachingConfigurationPropertySource cachingSource) {
|
||||
return cachingSource.getCaching();
|
||||
}
|
||||
|
||||
+3
@@ -22,6 +22,7 @@ import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.boot.origin.OriginProvider;
|
||||
import org.springframework.boot.origin.OriginTrackedValue;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -124,6 +125,7 @@ public final class ConfigurationProperty implements OriginProvider, Comparable<C
|
||||
return this.name.compareTo(other.name);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
static @Nullable ConfigurationProperty of(ConfigurationPropertyName name, @Nullable OriginTrackedValue value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
@@ -131,6 +133,7 @@ public final class ConfigurationProperty implements OriginProvider, Comparable<C
|
||||
return new ConfigurationProperty(name, value.getValue(), value.getOrigin());
|
||||
}
|
||||
|
||||
@Contract("_, _, !null, _ -> !null")
|
||||
static @Nullable ConfigurationProperty of(@Nullable ConfigurationPropertySource source,
|
||||
ConfigurationPropertyName name, @Nullable Object value, @Nullable Origin origin) {
|
||||
if (value == null) {
|
||||
|
||||
+5
-5
@@ -210,7 +210,7 @@ public final class ConfigurationPropertyName implements Comparable<Configuration
|
||||
* @return a new {@link ConfigurationPropertyName}
|
||||
* @throws InvalidConfigurationPropertyNameException if the result is not valid
|
||||
*/
|
||||
public ConfigurationPropertyName append(String suffix) {
|
||||
public ConfigurationPropertyName append(@Nullable String suffix) {
|
||||
if (!StringUtils.hasLength(suffix)) {
|
||||
return this;
|
||||
}
|
||||
@@ -625,7 +625,7 @@ public final class ConfigurationPropertyName implements Comparable<Configuration
|
||||
* @param name the name to test
|
||||
* @return {@code true} if the name is valid
|
||||
*/
|
||||
public static boolean isValid(CharSequence name) {
|
||||
public static boolean isValid(@Nullable CharSequence name) {
|
||||
return of(name, true) != null;
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ public final class ConfigurationPropertyName implements Comparable<Configuration
|
||||
* @throws InvalidConfigurationPropertyNameException if the name is not valid
|
||||
*/
|
||||
@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1232
|
||||
public static ConfigurationPropertyName of(CharSequence name) {
|
||||
public static ConfigurationPropertyName of(@Nullable CharSequence name) {
|
||||
return of(name, false);
|
||||
}
|
||||
|
||||
@@ -647,7 +647,7 @@ public final class ConfigurationPropertyName implements Comparable<Configuration
|
||||
* @return a {@link ConfigurationPropertyName} instance
|
||||
* @since 2.3.1
|
||||
*/
|
||||
public static @Nullable ConfigurationPropertyName ofIfValid(CharSequence name) {
|
||||
public static @Nullable ConfigurationPropertyName ofIfValid(@Nullable CharSequence name) {
|
||||
return of(name, true);
|
||||
}
|
||||
|
||||
@@ -660,7 +660,7 @@ public final class ConfigurationPropertyName implements Comparable<Configuration
|
||||
* {@code returnNullIfInvalid} is {@code false}
|
||||
*/
|
||||
@Contract("_, false -> !null")
|
||||
static @Nullable ConfigurationPropertyName of(CharSequence name, boolean returnNullIfInvalid) {
|
||||
static @Nullable ConfigurationPropertyName of(@Nullable CharSequence name, boolean returnNullIfInvalid) {
|
||||
Elements elements = elementsOf(name, returnNullIfInvalid, ElementsParser.DEFAULT_CAPACITY);
|
||||
return (elements != null) ? new ConfigurationPropertyName(elements) : null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public abstract class AbstractFailureAnalyzer<T extends Throwable> implements Fa
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final <E extends Throwable> @Nullable E findCause(Throwable failure, Class<E> type) {
|
||||
protected final <E extends Throwable> @Nullable E findCause(@Nullable Throwable failure, Class<E> type) {
|
||||
while (failure != null) {
|
||||
if (type.isInstance(failure)) {
|
||||
return (E) failure;
|
||||
|
||||
+2
-2
@@ -48,9 +48,9 @@ import org.springframework.core.env.PropertySource;
|
||||
class MutuallyExclusiveConfigurationPropertiesFailureAnalyzer
|
||||
extends AbstractFailureAnalyzer<MutuallyExclusiveConfigurationPropertiesException> {
|
||||
|
||||
private final ConfigurableEnvironment environment;
|
||||
private final @Nullable ConfigurableEnvironment environment;
|
||||
|
||||
MutuallyExclusiveConfigurationPropertiesFailureAnalyzer(Environment environment) {
|
||||
MutuallyExclusiveConfigurationPropertiesFailureAnalyzer(@Nullable Environment environment) {
|
||||
this.environment = (ConfigurableEnvironment) environment;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -34,11 +34,11 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public abstract class AbstractJsonParser implements JsonParser {
|
||||
|
||||
protected final Map<String, Object> parseMap(String json, Function<String, Map<String, Object>> parser) {
|
||||
protected final Map<String, Object> parseMap(@Nullable String json, Function<String, Map<String, Object>> parser) {
|
||||
return trimParse(json, "{", parser);
|
||||
}
|
||||
|
||||
protected final List<Object> parseList(String json, Function<String, List<Object>> parser) {
|
||||
protected final List<Object> parseList(@Nullable String json, Function<String, List<Object>> parser) {
|
||||
return trimParse(json, "[", parser);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,12 +44,12 @@ public class BasicJsonParser extends AbstractJsonParser {
|
||||
private static final int MAX_DEPTH = 1000;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseMap(String json) {
|
||||
public Map<String, Object> parseMap(@Nullable String json) {
|
||||
return tryParse(() -> parseMap(json, (jsonToParse) -> parseMapInternal(0, jsonToParse)), Exception.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> parseList(String json) {
|
||||
public List<Object> parseList(@Nullable String json) {
|
||||
return tryParse(() -> parseList(json, (jsonToParse) -> parseListInternal(0, jsonToParse)), Exception.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Thin wrapper to adapt {@link Gson} to a {@link JsonParser}.
|
||||
@@ -40,13 +41,13 @@ public class GsonJsonParser extends AbstractJsonParser {
|
||||
private final Gson gson = new GsonBuilder().create();
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseMap(String json) {
|
||||
public Map<String, Object> parseMap(@Nullable String json) {
|
||||
return tryParse(() -> parseMap(json, (trimmed) -> this.gson.fromJson(trimmed, MAP_TYPE.getType())),
|
||||
Exception.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> parseList(String json) {
|
||||
public List<Object> parseList(@Nullable String json) {
|
||||
return tryParse(() -> parseList(json, (trimmed) -> this.gson.fromJson(trimmed, LIST_TYPE.getType())),
|
||||
Exception.class);
|
||||
}
|
||||
|
||||
@@ -53,12 +53,12 @@ public class JacksonJsonParser extends AbstractJsonParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseMap(String json) {
|
||||
public Map<String, Object> parseMap(@Nullable String json) {
|
||||
return tryParse(() -> getObjectMapper().readValue(json, MAP_TYPE), Exception.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> parseList(String json) {
|
||||
public List<Object> parseList(@Nullable String json) {
|
||||
return tryParse(() -> getObjectMapper().readValue(json, LIST_TYPE), Exception.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.boot.json;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Parser that can read JSON formatted strings into {@link Map}s or {@link List}s.
|
||||
*
|
||||
@@ -37,7 +39,7 @@ public interface JsonParser {
|
||||
* @return the parsed JSON as a map
|
||||
* @throws JsonParseException if the JSON cannot be parsed
|
||||
*/
|
||||
Map<String, Object> parseMap(String json) throws JsonParseException;
|
||||
Map<String, Object> parseMap(@Nullable String json) throws JsonParseException;
|
||||
|
||||
/**
|
||||
* Parse the specified JSON string into a List.
|
||||
@@ -45,6 +47,6 @@ public interface JsonParser {
|
||||
* @return the parsed JSON as a list
|
||||
* @throws JsonParseException if the JSON cannot be parsed
|
||||
*/
|
||||
List<Object> parseList(String json) throws JsonParseException;
|
||||
List<Object> parseList(@Nullable String json) throws JsonParseException;
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,13 +28,13 @@ import org.jspecify.annotations.Nullable;
|
||||
*/
|
||||
class DelegatingLoggingSystemFactory implements LoggingSystemFactory {
|
||||
|
||||
private final @Nullable Function<ClassLoader, List<LoggingSystemFactory>> delegates;
|
||||
private final @Nullable Function<ClassLoader, @Nullable List<LoggingSystemFactory>> delegates;
|
||||
|
||||
/**
|
||||
* Create a new {@link DelegatingLoggingSystemFactory} instance.
|
||||
* @param delegates a function that provides the delegates
|
||||
*/
|
||||
DelegatingLoggingSystemFactory(@Nullable Function<ClassLoader, List<LoggingSystemFactory>> delegates) {
|
||||
DelegatingLoggingSystemFactory(@Nullable Function<ClassLoader, @Nullable List<LoggingSystemFactory>> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ public final class ColorConverter extends LogEventPatternConverter {
|
||||
* @param options the options
|
||||
* @return a new instance, or {@code null} if the options are invalid
|
||||
*/
|
||||
public static @Nullable ColorConverter newInstance(Configuration config, @Nullable String[] options) {
|
||||
public static @Nullable ColorConverter newInstance(@Nullable Configuration config, @Nullable String[] options) {
|
||||
if (options.length < 1) {
|
||||
LOGGER.error("Incorrect number of options on style. Expected at least 1, received {}", options.length);
|
||||
return null;
|
||||
|
||||
+2
-1
@@ -67,7 +67,8 @@ public final class EnclosedInSquareBracketsConverter extends LogEventPatternConv
|
||||
* @param options the options
|
||||
* @return a new instance, or {@code null} if the options are invalid
|
||||
*/
|
||||
public static @Nullable EnclosedInSquareBracketsConverter newInstance(Configuration config, String[] options) {
|
||||
public static @Nullable EnclosedInSquareBracketsConverter newInstance(@Nullable Configuration config,
|
||||
String[] options) {
|
||||
if (options.length < 1) {
|
||||
LOGGER.error("Incorrect number of options on style. Expected at least 1, received {}", options.length);
|
||||
return null;
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ import org.springframework.util.StringUtils;
|
||||
public class EnclosedInSquareBracketsConverter extends CompositeConverter<ILoggingEvent> {
|
||||
|
||||
@Override
|
||||
protected String transform(ILoggingEvent event, String in) {
|
||||
protected String transform(ILoggingEvent event, @Nullable String in) {
|
||||
in = (!StringUtils.hasLength(in)) ? resolveFromFirstOption(event) : in;
|
||||
return (!StringUtils.hasLength(in)) ? "" : "[%s] ".formatted(in);
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ public class LogbackLoggingSystemProperties extends LoggingSystemProperties {
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public LogbackLoggingSystemProperties(Environment environment,
|
||||
Function<@Nullable String, @Nullable String> defaultValueResolver,
|
||||
@Nullable Function<@Nullable String, @Nullable String> defaultValueResolver,
|
||||
@Nullable BiConsumer<String, @Nullable String> setter) {
|
||||
super(environment, defaultValueResolver, setter);
|
||||
}
|
||||
|
||||
+5
-4
@@ -56,11 +56,11 @@ import org.springframework.util.Assert;
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
record StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude, Map<String, String> rename,
|
||||
Map<String, String> add, StackTrace stackTrace, Context context,
|
||||
Map<String, String> add, @Nullable StackTrace stackTrace, @Nullable Context context,
|
||||
Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {
|
||||
|
||||
StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude, Map<String, String> rename,
|
||||
Map<String, String> add, StackTrace stackTrace, Context context,
|
||||
Map<String, String> add, @Nullable StackTrace stackTrace, @Nullable Context context,
|
||||
@Nullable Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {
|
||||
this.include = include;
|
||||
this.exclude = exclude;
|
||||
@@ -98,8 +98,9 @@ record StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude,
|
||||
* @param includeCommonFrames whether common frames should be included
|
||||
* @param includeHashes whether stack trace hashes should be included
|
||||
*/
|
||||
record StackTrace(@Nullable String printer, Root root, Integer maxLength, Integer maxThrowableDepth,
|
||||
Boolean includeCommonFrames, Boolean includeHashes) {
|
||||
record StackTrace(@Nullable String printer, @Nullable Root root, @Nullable Integer maxLength,
|
||||
@Nullable Integer maxThrowableDepth, @Nullable Boolean includeCommonFrames,
|
||||
@Nullable Boolean includeHashes) {
|
||||
|
||||
@Nullable StackTracePrinter createPrinter() {
|
||||
String name = sanitizePrinter();
|
||||
|
||||
@@ -47,7 +47,7 @@ public interface OriginLookup<K> {
|
||||
* @return an {@link Origin} or {@code null}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K> @Nullable Origin getOrigin(Object source, K key) {
|
||||
static <K> @Nullable Origin getOrigin(@Nullable Object source, K key) {
|
||||
if (!(source instanceof OriginLookup)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public record JksSslStoreDetails(@Nullable String type, @Nullable String provide
|
||||
* @param location the location
|
||||
* @return a new {@link JksSslStoreDetails} instance.
|
||||
*/
|
||||
public static JksSslStoreDetails forLocation(String location) {
|
||||
public static JksSslStoreDetails forLocation(@Nullable String location) {
|
||||
return new JksSslStoreDetails(null, null, location, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@ public interface PemSslStore {
|
||||
* @return a new {@link PemSslStore} instance
|
||||
*/
|
||||
default PemSslStore withAlias(@Nullable String alias) {
|
||||
return of(type(), alias, password(), certificates(), privateKey());
|
||||
List<X509Certificate> certificates = certificates();
|
||||
Assert.notNull(certificates, "'certificates' must not be null");
|
||||
return of(type(), alias, password(), certificates, privateKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +89,9 @@ public interface PemSslStore {
|
||||
* @return a new {@link PemSslStore} instance
|
||||
*/
|
||||
default PemSslStore withPassword(@Nullable String password) {
|
||||
return of(type(), alias(), password, certificates(), privateKey());
|
||||
List<X509Certificate> certificates = certificates();
|
||||
Assert.notNull(certificates, "'certificates' must not be null");
|
||||
return of(type(), alias(), password, certificates, privateKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +127,7 @@ public interface PemSslStore {
|
||||
* @param privateKey the private key
|
||||
* @return a new {@link PemSslStore} instance
|
||||
*/
|
||||
static PemSslStore of(String type, List<X509Certificate> certificates, PrivateKey privateKey) {
|
||||
static PemSslStore of(@Nullable String type, List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {
|
||||
return of(type, null, null, certificates, privateKey);
|
||||
}
|
||||
|
||||
@@ -134,7 +138,7 @@ public interface PemSslStore {
|
||||
* @param privateKey the private key
|
||||
* @return a new {@link PemSslStore} instance
|
||||
*/
|
||||
static PemSslStore of(List<X509Certificate> certificates, PrivateKey privateKey) {
|
||||
static PemSslStore of(List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {
|
||||
return of(null, null, null, certificates, privateKey);
|
||||
}
|
||||
|
||||
@@ -151,7 +155,7 @@ public interface PemSslStore {
|
||||
* @return a new {@link PemSslStore} instance
|
||||
*/
|
||||
static PemSslStore of(@Nullable String type, @Nullable String alias, @Nullable String password,
|
||||
@Nullable List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {
|
||||
List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {
|
||||
Assert.notEmpty(certificates, "'certificates' must not be empty");
|
||||
return new PemSslStore() {
|
||||
|
||||
|
||||
+2
-2
@@ -151,7 +151,7 @@ public record PemSslStoreDetails(@Nullable String type, @Nullable String alias,
|
||||
* reference to the resource to load)
|
||||
* @return a new {@link PemSslStoreDetails} instance.
|
||||
*/
|
||||
public static PemSslStoreDetails forCertificate(String certificate) {
|
||||
public static PemSslStoreDetails forCertificate(@Nullable String certificate) {
|
||||
return forCertificates(certificate);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ public record PemSslStoreDetails(@Nullable String type, @Nullable String alias,
|
||||
* @return a new {@link PemSslStoreDetails} instance.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static PemSslStoreDetails forCertificates(String certificates) {
|
||||
public static PemSslStoreDetails forCertificates(@Nullable String certificates) {
|
||||
return new PemSslStoreDetails(null, certificates, null);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ApplicationPid {
|
||||
this.pid = currentProcessPid();
|
||||
}
|
||||
|
||||
protected ApplicationPid(Long pid) {
|
||||
protected ApplicationPid(@Nullable Long pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -151,7 +151,7 @@ public abstract class SpringBootServletInitializer implements WebApplicationInit
|
||||
}
|
||||
}
|
||||
|
||||
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
|
||||
protected @Nullable WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
|
||||
SpringApplicationBuilder builder = createSpringApplicationBuilder();
|
||||
builder.main(getClass());
|
||||
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
|
||||
@@ -201,7 +201,7 @@ public abstract class SpringBootServletInitializer implements WebApplicationInit
|
||||
* @param application the application to run
|
||||
* @return the {@link WebApplicationContext}
|
||||
*/
|
||||
protected WebApplicationContext run(SpringApplication application) {
|
||||
protected @Nullable WebApplicationContext run(SpringApplication application) {
|
||||
return (WebApplicationContext) application.run();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user