mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-01 14:59:50 +00:00
Add nullability annotations to core/spring-boot-test
See gh-46587
This commit is contained in:
+8
-4
@@ -22,6 +22,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
@@ -63,7 +65,7 @@ public final class AnnotatedClassFinder {
|
||||
* @return the first {@link Class} annotated with the target annotation within the
|
||||
* hierarchy defined by the given {@code source} or {@code null} if none is found.
|
||||
*/
|
||||
public Class<?> findFromClass(Class<?> source) {
|
||||
public @Nullable Class<?> findFromClass(Class<?> source) {
|
||||
Assert.notNull(source, "'source' must not be null");
|
||||
return findFromPackage(ClassUtils.getPackageName(source));
|
||||
}
|
||||
@@ -75,7 +77,7 @@ public final class AnnotatedClassFinder {
|
||||
* @return the first {@link Class} annotated with the target annotation within the
|
||||
* hierarchy defined by the given {@code source} or {@code null} if none is found.
|
||||
*/
|
||||
public Class<?> findFromPackage(String source) {
|
||||
public @Nullable Class<?> findFromPackage(String source) {
|
||||
Assert.notNull(source, "'source' must not be null");
|
||||
Class<?> configuration = cache.get(source);
|
||||
if (configuration == null) {
|
||||
@@ -85,13 +87,15 @@ public final class AnnotatedClassFinder {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private Class<?> scanPackage(String source) {
|
||||
private @Nullable Class<?> scanPackage(String source) {
|
||||
while (!source.isEmpty()) {
|
||||
Set<BeanDefinition> components = this.scanner.findCandidateComponents(source);
|
||||
if (!components.isEmpty()) {
|
||||
Assert.state(components.size() == 1, () -> "Found multiple @" + this.annotationType.getSimpleName()
|
||||
+ " annotated classes " + components);
|
||||
return ClassUtils.resolveClassName(components.iterator().next().getBeanClassName(), null);
|
||||
String beanClassName = components.iterator().next().getBeanClassName();
|
||||
Assert.state(beanClassName != null, "'beanClassName' must not be null");
|
||||
return ClassUtils.resolveClassName(beanClassName, null);
|
||||
}
|
||||
source = getParentPackage(source);
|
||||
}
|
||||
|
||||
+5
-3
@@ -27,6 +27,8 @@ import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
@@ -117,7 +119,7 @@ public class FilteredClassLoader extends URLClassLoader implements SmartClassLoa
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
public @Nullable URL getResource(String name) {
|
||||
for (Predicate<String> filter : this.resourcesFilters) {
|
||||
if (filter.test(name)) {
|
||||
return null;
|
||||
@@ -137,7 +139,7 @@ public class FilteredClassLoader extends URLClassLoader implements SmartClassLoa
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
public @Nullable InputStream getResourceAsStream(String name) {
|
||||
for (Predicate<String> filter : this.resourcesFilters) {
|
||||
if (filter.test(name)) {
|
||||
return null;
|
||||
@@ -147,7 +149,7 @@ public class FilteredClassLoader extends URLClassLoader implements SmartClassLoa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> publicDefineClass(String name, byte[] b, ProtectionDomain protectionDomain) {
|
||||
public Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) {
|
||||
for (Predicate<String> filter : this.classesFilters) {
|
||||
if (filter.test(name)) {
|
||||
throw new IllegalArgumentException(String.format("Defining class with name %s is not supported", name));
|
||||
|
||||
+5
-2
@@ -24,6 +24,8 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
@@ -156,6 +158,7 @@ class ImportsContextCustomizer implements ContextCustomizer {
|
||||
|
||||
private static final String[] NO_IMPORTS = {};
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
@@ -254,7 +257,7 @@ class ImportsContextCustomizer implements ContextCustomizer {
|
||||
return ANNOTATION_FILTERS.stream().anyMatch((filter) -> filter.matches(typeName));
|
||||
}
|
||||
|
||||
private Set<Object> determineImports(MergedAnnotations annotations, Class<?> testClass) {
|
||||
private @Nullable Set<Object> determineImports(MergedAnnotations annotations, Class<?> testClass) {
|
||||
Set<Object> determinedImports = new LinkedHashSet<>();
|
||||
AnnotationMetadata metadata = AnnotationMetadata.introspect(testClass);
|
||||
for (MergedAnnotation<Import> annotation : annotations.stream(Import.class).toList()) {
|
||||
@@ -269,7 +272,7 @@ class ImportsContextCustomizer implements ContextCustomizer {
|
||||
return determinedImports;
|
||||
}
|
||||
|
||||
private Set<Object> determineImports(Class<?> source, AnnotationMetadata metadata) {
|
||||
private @Nullable Set<Object> determineImports(Class<?> source, AnnotationMetadata metadata) {
|
||||
if (DeterminableImports.class.isAssignableFrom(source)) {
|
||||
// We can determine the imports
|
||||
return ((DeterminableImports) instantiate(source)).determineImports(metadata);
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ package org.springframework.boot.test.context;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.AotDetector;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -41,7 +43,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
class ImportsContextCustomizerFactory implements ContextCustomizerFactory {
|
||||
|
||||
@Override
|
||||
public ContextCustomizer createContextCustomizer(Class<?> testClass,
|
||||
public @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,
|
||||
List<ContextConfigurationAttributes> configAttributes) {
|
||||
if (AotDetector.useGeneratedArtifacts()) {
|
||||
return null;
|
||||
|
||||
+24
-16
@@ -23,6 +23,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -105,6 +107,8 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
private static final Consumer<SpringApplication> ALREADY_CONFIGURED = (springApplication) -> {
|
||||
};
|
||||
|
||||
private static final Object NONE = new Object();
|
||||
|
||||
@Override
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
return loadContext(mergedConfig, Mode.STANDARD, null, null);
|
||||
@@ -123,8 +127,8 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
}
|
||||
|
||||
private ApplicationContext loadContext(MergedContextConfiguration mergedConfig, Mode mode,
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext> initializer, RuntimeHints runtimeHints)
|
||||
throws Exception {
|
||||
@Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer,
|
||||
@Nullable RuntimeHints runtimeHints) throws Exception {
|
||||
assertHasClassesOrLocations(mergedConfig);
|
||||
SpringBootTestAnnotation annotation = SpringBootTestAnnotation.get(mergedConfig);
|
||||
String[] args = annotation.getArgs();
|
||||
@@ -153,7 +157,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
+ SpringVersion.getVersion() + ").");
|
||||
}
|
||||
|
||||
private Method getMainMethod(MergedContextConfiguration mergedConfig, UseMainMethod useMainMethod) {
|
||||
private @Nullable Method getMainMethod(MergedContextConfiguration mergedConfig, UseMainMethod useMainMethod) {
|
||||
if (useMainMethod == UseMainMethod.NEVER) {
|
||||
return null;
|
||||
}
|
||||
@@ -167,14 +171,16 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
"Cannot use main method as no @SpringBootConfiguration-annotated class is available");
|
||||
Method mainMethod = findMainMethod(springBootConfiguration);
|
||||
Assert.state(mainMethod != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE,
|
||||
() -> "Main method not found on '%s'".formatted(springBootConfiguration.getName()));
|
||||
() -> "Main method not found on '%s'"
|
||||
.formatted((springBootConfiguration != null) ? springBootConfiguration.getName() : null));
|
||||
return mainMethod;
|
||||
}
|
||||
|
||||
private static Method findMainMethod(Class<?> type) {
|
||||
private static @Nullable Method findMainMethod(@Nullable Class<?> type) {
|
||||
Method mainMethod = (type != null) ? ReflectionUtils.findMethod(type, "main", String[].class) : null;
|
||||
if (mainMethod == null && KotlinDetector.isKotlinPresent()) {
|
||||
try {
|
||||
Assert.state(type != null, "'type' must not be null");
|
||||
Class<?> kotlinClass = ClassUtils.forName(type.getName() + "Kt", type.getClassLoader());
|
||||
mainMethod = ReflectionUtils.findMethod(kotlinClass, "main", String[].class);
|
||||
}
|
||||
@@ -285,7 +291,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
* method if you need a custom environment.
|
||||
* @return a {@link ConfigurableEnvironment} instance
|
||||
*/
|
||||
protected ConfigurableEnvironment getEnvironment() {
|
||||
protected @Nullable ConfigurableEnvironment getEnvironment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -462,9 +468,9 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
private static class ParentContextApplicationContextInitializer
|
||||
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
private final ApplicationContext parent;
|
||||
private final @Nullable ApplicationContext parent;
|
||||
|
||||
ParentContextApplicationContextInitializer(ApplicationContext parent) {
|
||||
ParentContextApplicationContextInitializer(@Nullable ApplicationContext parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@@ -507,7 +513,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
|
||||
private final Mode mode;
|
||||
|
||||
private final ApplicationContextInitializer<ConfigurableApplicationContext> initializer;
|
||||
private final @Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer;
|
||||
|
||||
private final Consumer<SpringApplication> configurer;
|
||||
|
||||
@@ -515,7 +521,8 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
|
||||
private final List<ApplicationContext> failedContexts = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
ContextLoaderHook(Mode mode, ApplicationContextInitializer<ConfigurableApplicationContext> initializer,
|
||||
ContextLoaderHook(Mode mode,
|
||||
@Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer,
|
||||
Consumer<SpringApplication> configurer) {
|
||||
this.mode = mode;
|
||||
this.initializer = initializer;
|
||||
@@ -530,6 +537,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
public void starting(ConfigurableBootstrapContext bootstrapContext) {
|
||||
ContextLoaderHook.this.configurer.accept(application);
|
||||
if (ContextLoaderHook.this.mode == Mode.AOT_RUNTIME) {
|
||||
Assert.state(ContextLoaderHook.this.initializer != null, "'initializer' must not be null");
|
||||
application.addInitializers(
|
||||
(AotApplicationContextInitializer<?>) ContextLoaderHook.this.initializer::initialize);
|
||||
}
|
||||
@@ -544,24 +552,24 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
public void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {
|
||||
ContextLoaderHook.this.failedContexts.add(context);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private <T> ApplicationContext runMain(Runnable action) throws Exception {
|
||||
private ApplicationContext runMain(Runnable action) throws Exception {
|
||||
return run(() -> {
|
||||
action.run();
|
||||
return null;
|
||||
return NONE;
|
||||
});
|
||||
}
|
||||
|
||||
private ApplicationContext run(ThrowingSupplier<ConfigurableApplicationContext> action) throws Exception {
|
||||
private ApplicationContext run(ThrowingSupplier<?> action) throws Exception {
|
||||
try {
|
||||
ConfigurableApplicationContext context = SpringApplication.withHook(this, action);
|
||||
if (context != null) {
|
||||
Object result = SpringApplication.withHook(this, action);
|
||||
if (result instanceof ApplicationContext context) {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -19,6 +19,8 @@ package org.springframework.boot.test.context;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -52,7 +54,7 @@ class SpringBootTestAnnotation implements ContextCustomizer {
|
||||
this(TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class));
|
||||
}
|
||||
|
||||
private SpringBootTestAnnotation(SpringBootTest annotation) {
|
||||
private SpringBootTestAnnotation(@Nullable SpringBootTest annotation) {
|
||||
this.args = (annotation != null) ? annotation.args() : NO_ARGS;
|
||||
this.webEnvironment = (annotation != null) ? annotation.webEnvironment() : WebEnvironment.NONE;
|
||||
this.useMainMethod = (annotation != null) ? annotation.useMainMethod() : UseMainMethod.NEVER;
|
||||
|
||||
+6
-5
@@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
@@ -287,7 +288,7 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
||||
* the bootstrapper class as a property.
|
||||
* @return the differentiator or {@code null}
|
||||
*/
|
||||
protected String getDifferentiatorPropertySourceProperty() {
|
||||
protected @Nullable String getDifferentiatorPropertySourceProperty() {
|
||||
return getClass().getName() + "=true";
|
||||
}
|
||||
|
||||
@@ -320,22 +321,22 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
||||
* @param testClass the source test class
|
||||
* @return the {@link WebEnvironment} or {@code null}
|
||||
*/
|
||||
protected WebEnvironment getWebEnvironment(Class<?> testClass) {
|
||||
protected @Nullable WebEnvironment getWebEnvironment(Class<?> testClass) {
|
||||
SpringBootTest annotation = getAnnotation(testClass);
|
||||
return (annotation != null) ? annotation.webEnvironment() : null;
|
||||
}
|
||||
|
||||
protected Class<?>[] getClasses(Class<?> testClass) {
|
||||
protected Class<?> @Nullable [] getClasses(Class<?> testClass) {
|
||||
SpringBootTest annotation = getAnnotation(testClass);
|
||||
return (annotation != null) ? annotation.classes() : null;
|
||||
}
|
||||
|
||||
protected String[] getProperties(Class<?> testClass) {
|
||||
protected String @Nullable [] getProperties(Class<?> testClass) {
|
||||
SpringBootTest annotation = getAnnotation(testClass);
|
||||
return (annotation != null) ? annotation.properties() : null;
|
||||
}
|
||||
|
||||
protected SpringBootTest getAnnotation(Class<?> testClass) {
|
||||
protected @Nullable SpringBootTest getAnnotation(Class<?> testClass) {
|
||||
return TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class);
|
||||
}
|
||||
|
||||
|
||||
+28
-18
@@ -29,6 +29,7 @@ import org.assertj.core.api.AbstractThrowableAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
@@ -54,14 +55,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
extends AbstractAssert<ApplicationContextAssert<C>, C> {
|
||||
|
||||
private final Throwable startupFailure;
|
||||
private final @Nullable Throwable startupFailure;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationContextAssert} instance.
|
||||
* @param applicationContext the source application context
|
||||
* @param startupFailure the startup failure or {@code null}
|
||||
*/
|
||||
ApplicationContextAssert(C applicationContext, Throwable startupFailure) {
|
||||
ApplicationContextAssert(C applicationContext, @Nullable Throwable startupFailure) {
|
||||
super(applicationContext, ApplicationContextAssert.class);
|
||||
Assert.notNull(applicationContext, "'applicationContext' must not be null");
|
||||
this.startupFailure = startupFailure;
|
||||
@@ -80,7 +81,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
*/
|
||||
public ApplicationContextAssert<C> hasBean(String name) {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to have bean named:%n <%s>", name));
|
||||
throwAssertionError(
|
||||
contextFailedToStartWhenExpecting(this.startupFailure, "to have bean named:%n <%s>", name));
|
||||
}
|
||||
if (findBean(name) == null) {
|
||||
throwAssertionError(new BasicErrorMessageFactory(
|
||||
@@ -123,7 +125,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
public ApplicationContextAssert<C> hasSingleBean(Class<?> type, Scope scope) {
|
||||
Assert.notNull(scope, "'scope' must not be null");
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to have a single bean of type:%n <%s>", type));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,
|
||||
"to have a single bean of type:%n <%s>", type));
|
||||
}
|
||||
String[] names = scope.getBeanNamesForType(getApplicationContext(), type);
|
||||
if (names.length == 0) {
|
||||
@@ -170,7 +173,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
public ApplicationContextAssert<C> doesNotHaveBean(Class<?> type, Scope scope) {
|
||||
Assert.notNull(scope, "'scope' must not be null");
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("not to have any beans of type:%n <%s>", type));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,
|
||||
"not to have any beans of type:%n <%s>", type));
|
||||
}
|
||||
String[] names = scope.getBeanNamesForType(getApplicationContext(), type);
|
||||
if (names.length > 0) {
|
||||
@@ -194,7 +198,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
*/
|
||||
public ApplicationContextAssert<C> doesNotHaveBean(String name) {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("not to have any beans of name:%n <%s>", name));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,
|
||||
"not to have any beans of name:%n <%s>", name));
|
||||
}
|
||||
try {
|
||||
Object bean = getApplicationContext().getBean(name);
|
||||
@@ -221,7 +226,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
*/
|
||||
public <T> AbstractObjectArrayAssert<?, String> getBeanNames(Class<T> type) {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to get beans names with type:%n <%s>", type));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,
|
||||
"to get beans names with type:%n <%s>", type));
|
||||
}
|
||||
return Assertions.assertThat(getApplicationContext().getBeanNamesForType(type))
|
||||
.as("Bean names of type <%s> from <%s>", type, getApplicationContext());
|
||||
@@ -267,7 +273,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
public <T> AbstractObjectAssert<?, T> getBean(Class<T> type, Scope scope) {
|
||||
Assert.notNull(scope, "'scope' must not be null");
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to contain bean of type:%n <%s>", type));
|
||||
throwAssertionError(
|
||||
contextFailedToStartWhenExpecting(this.startupFailure, "to contain bean of type:%n <%s>", type));
|
||||
}
|
||||
String[] names = scope.getBeanNamesForType(getApplicationContext(), type);
|
||||
String name = (names.length > 0) ? getPrimary(names, scope) : null;
|
||||
@@ -280,7 +287,7 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
return Assertions.assertThat(bean).as("Bean of type <%s> from <%s>", type, getApplicationContext());
|
||||
}
|
||||
|
||||
private String getPrimary(String[] names, Scope scope) {
|
||||
private @Nullable String getPrimary(String[] names, Scope scope) {
|
||||
if (names.length == 1) {
|
||||
return names[0];
|
||||
}
|
||||
@@ -325,7 +332,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
*/
|
||||
public AbstractObjectAssert<?, Object> getBean(String name) {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to contain a bean of name:%n <%s>", name));
|
||||
throwAssertionError(
|
||||
contextFailedToStartWhenExpecting(this.startupFailure, "to contain a bean of name:%n <%s>", name));
|
||||
}
|
||||
Object bean = findBean(name);
|
||||
return Assertions.assertThat(bean).as("Bean of name <%s> from <%s>", name, getApplicationContext());
|
||||
@@ -351,8 +359,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> AbstractObjectAssert<?, T> getBean(String name, Class<T> type) {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(
|
||||
contextFailedToStartWhenExpecting("to contain a bean of name:%n <%s> (%s)", name, type));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,
|
||||
"to contain a bean of name:%n <%s> (%s)", name, type));
|
||||
}
|
||||
Object bean = findBean(name);
|
||||
if (bean != null && type != null && !type.isInstance(bean)) {
|
||||
@@ -364,7 +372,7 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
.as("Bean of name <%s> and type <%s> from <%s>", name, type, getApplicationContext());
|
||||
}
|
||||
|
||||
private Object findBean(String name) {
|
||||
private @Nullable Object findBean(String name) {
|
||||
try {
|
||||
return getApplicationContext().getBean(name);
|
||||
}
|
||||
@@ -409,7 +417,8 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
public <T> MapAssert<String, T> getBeans(Class<T> type, Scope scope) {
|
||||
Assert.notNull(scope, "'scope' must not be null");
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to get beans of type:%n <%s>", type));
|
||||
throwAssertionError(
|
||||
contextFailedToStartWhenExpecting(this.startupFailure, "to get beans of type:%n <%s>", type));
|
||||
}
|
||||
return Assertions.assertThat(scope.getBeansOfType(getApplicationContext(), type))
|
||||
.as("Beans of type <%s> from <%s>", type, getApplicationContext());
|
||||
@@ -456,7 +465,7 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
*/
|
||||
public ApplicationContextAssert<C> hasNotFailed() {
|
||||
if (this.startupFailure != null) {
|
||||
throwAssertionError(contextFailedToStartWhenExpecting("to have not failed"));
|
||||
throwAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, "to have not failed"));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -465,12 +474,13 @@ public class ApplicationContextAssert<C extends ApplicationContext>
|
||||
return this.actual;
|
||||
}
|
||||
|
||||
protected final Throwable getStartupFailure() {
|
||||
protected final @Nullable Throwable getStartupFailure() {
|
||||
return this.startupFailure;
|
||||
}
|
||||
|
||||
private ContextFailedToStart<C> contextFailedToStartWhenExpecting(String expectationFormat, Object... arguments) {
|
||||
return new ContextFailedToStart<>(getApplicationContext(), this.startupFailure, expectationFormat, arguments);
|
||||
private ContextFailedToStart<C> contextFailedToStartWhenExpecting(Throwable startupFailure,
|
||||
String expectationFormat, Object... arguments) {
|
||||
return new ContextFailedToStart<>(getApplicationContext(), startupFailure, expectationFormat, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -86,7 +87,7 @@ public interface ApplicationContextAssertProvider<C extends ApplicationContext>
|
||||
* context started without issue.
|
||||
* @return the startup failure or {@code null}
|
||||
*/
|
||||
Throwable getStartupFailure();
|
||||
@Nullable Throwable getStartupFailure();
|
||||
|
||||
@Override
|
||||
void close();
|
||||
|
||||
+9
-5
@@ -24,6 +24,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,9 +41,9 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
|
||||
private final Class<?> applicationContextType;
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
private final @Nullable ApplicationContext applicationContext;
|
||||
|
||||
private final RuntimeException startupFailure;
|
||||
private final @Nullable RuntimeException startupFailure;
|
||||
|
||||
AssertProviderApplicationContextInvocationHandler(Class<?> applicationContextType, Supplier<?> contextSupplier) {
|
||||
this.applicationContextType = applicationContextType;
|
||||
@@ -66,7 +68,7 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (isToString(method)) {
|
||||
return toString();
|
||||
}
|
||||
@@ -95,6 +97,7 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
return "Unstarted application context " + this.applicationContextType.getName() + "[startupFailure="
|
||||
+ this.startupFailure.getClass().getName() + "]";
|
||||
}
|
||||
Assert.state(this.applicationContext != null, "'applicationContext' must not be null");
|
||||
ToStringCreator builder = new ToStringCreator(this.applicationContext)
|
||||
.append("id", this.applicationContext.getId())
|
||||
.append("applicationName", this.applicationContext.getApplicationName())
|
||||
@@ -119,7 +122,7 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
return ("getStartupFailure".equals(method.getName()) && method.getParameterCount() == 0);
|
||||
}
|
||||
|
||||
private Object getStartupFailure() {
|
||||
private @Nullable Object getStartupFailure() {
|
||||
return this.startupFailure;
|
||||
}
|
||||
|
||||
@@ -135,7 +138,7 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
return ("close".equals(method.getName()) && method.getParameterCount() == 0);
|
||||
}
|
||||
|
||||
private Object invokeClose() throws IOException {
|
||||
private @Nullable Object invokeClose() throws IOException {
|
||||
if (this.applicationContext instanceof Closeable closeable) {
|
||||
closeable.close();
|
||||
}
|
||||
@@ -155,6 +158,7 @@ class AssertProviderApplicationContextInvocationHandler implements InvocationHan
|
||||
if (this.startupFailure != null) {
|
||||
throw new IllegalStateException(this + " failed to start", this.startupFailure);
|
||||
}
|
||||
Assert.state(this.applicationContext != null, "'applicationContext' must not be null");
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* AssertJ support for ApplicationContexts.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.context.assertj;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ package org.springframework.boot.test.context.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.context.TypeExcludeFilter;
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
@@ -68,7 +70,7 @@ class TestTypeExcludeFilter extends TypeExcludeFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return (obj != null) && (getClass() == obj.getClass());
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Test support for {@link org.springframework.boot.context.TypeExcludeFilter}.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.context.filter;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -18,4 +18,7 @@
|
||||
* Classes and annotations related to configuring Spring's {@code ApplicationContext} for
|
||||
* tests.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+15
-11
@@ -24,6 +24,8 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
@@ -213,7 +215,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
* @return a new instance with the updated class loader
|
||||
* @see FilteredClassLoader
|
||||
*/
|
||||
public SELF withClassLoader(ClassLoader classLoader) {
|
||||
public SELF withClassLoader(@Nullable ClassLoader classLoader) {
|
||||
return newInstance(this.runnerConfiguration.withClassLoader(classLoader));
|
||||
}
|
||||
|
||||
@@ -258,7 +260,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(String name, Class<T> type, Object... constructorArgs) {
|
||||
public <T> SELF withBean(@Nullable String name, Class<T> type, Object... constructorArgs) {
|
||||
return newInstance(this.runnerConfiguration.withBean(name, type, constructorArgs));
|
||||
}
|
||||
|
||||
@@ -295,7 +297,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(String name, Class<T> type, Supplier<T> supplier,
|
||||
public <T> SELF withBean(@Nullable String name, Class<T> type, Supplier<T> supplier,
|
||||
BeanDefinitionCustomizer... customizers) {
|
||||
return newInstance(this.runnerConfiguration.withBean(name, type, supplier, customizers));
|
||||
}
|
||||
@@ -370,7 +372,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
}
|
||||
}
|
||||
|
||||
private void withContextClassLoader(ClassLoader classLoader, Runnable action) {
|
||||
private void withContextClassLoader(@Nullable ClassLoader classLoader, Runnable action) {
|
||||
if (classLoader == null) {
|
||||
action.run();
|
||||
}
|
||||
@@ -392,6 +394,8 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
ResolvableType resolvableType = ResolvableType.forClass(AbstractApplicationContextRunner.class, getClass());
|
||||
Class<A> assertType = (Class<A>) resolvableType.resolveGeneric(1);
|
||||
Class<C> contextType = (Class<C>) resolvableType.resolveGeneric(2);
|
||||
Assert.state(assertType != null, "'assertType' must not be null");
|
||||
Assert.state(contextType != null, "'contextType' must not be null");
|
||||
return ApplicationContextAssertProvider.get(assertType, contextType, () -> createAndLoadContext(refresh),
|
||||
this.runnerConfiguration.additionalContextInterfaces);
|
||||
}
|
||||
@@ -471,11 +475,11 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
|
||||
Consumer<GenericApplicationContext> registrar;
|
||||
|
||||
public BeanRegistration(String name, Class<T> type, Object... constructorArgs) {
|
||||
public BeanRegistration(@Nullable String name, Class<T> type, Object... constructorArgs) {
|
||||
this.registrar = (context) -> context.registerBean(name, type, constructorArgs);
|
||||
}
|
||||
|
||||
public BeanRegistration(String name, Class<T> type, Supplier<T> supplier,
|
||||
public BeanRegistration(@Nullable String name, Class<T> type, Supplier<T> supplier,
|
||||
BeanDefinitionCustomizer... customizers) {
|
||||
this.registrar = (context) -> context.registerBean(name, type, supplier, customizers);
|
||||
}
|
||||
@@ -503,9 +507,9 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
|
||||
private TestPropertyValues systemProperties = TestPropertyValues.empty();
|
||||
|
||||
private ClassLoader classLoader;
|
||||
private @Nullable ClassLoader classLoader;
|
||||
|
||||
private ApplicationContext parent;
|
||||
private @Nullable ApplicationContext parent;
|
||||
|
||||
private List<BeanRegistration<?>> beanRegistrations = Collections.emptyList();
|
||||
|
||||
@@ -561,7 +565,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
return config;
|
||||
}
|
||||
|
||||
private RunnerConfiguration<C> withClassLoader(ClassLoader classLoader) {
|
||||
private RunnerConfiguration<C> withClassLoader(@Nullable ClassLoader classLoader) {
|
||||
RunnerConfiguration<C> config = new RunnerConfiguration<>(this);
|
||||
config.classLoader = classLoader;
|
||||
return config;
|
||||
@@ -573,14 +577,14 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
||||
return config;
|
||||
}
|
||||
|
||||
private <T> RunnerConfiguration<C> withBean(String name, Class<T> type, Object... constructorArgs) {
|
||||
private <T> RunnerConfiguration<C> withBean(@Nullable String name, Class<T> type, Object... constructorArgs) {
|
||||
RunnerConfiguration<C> config = new RunnerConfiguration<>(this);
|
||||
config.beanRegistrations = add(config.beanRegistrations,
|
||||
new BeanRegistration<>(name, type, constructorArgs));
|
||||
return config;
|
||||
}
|
||||
|
||||
private <T> RunnerConfiguration<C> withBean(String name, Class<T> type, Supplier<T> supplier,
|
||||
private <T> RunnerConfiguration<C> withBean(@Nullable String name, Class<T> type, Supplier<T> supplier,
|
||||
BeanDefinitionCustomizer... customizers) {
|
||||
RunnerConfiguration<C> config = new RunnerConfiguration<>(this);
|
||||
config.beanRegistrations = add(config.beanRegistrations,
|
||||
|
||||
+6
-2
@@ -18,8 +18,11 @@ package org.springframework.boot.test.context.runner;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
@@ -81,8 +84,9 @@ public final class WebApplicationContextRunner extends
|
||||
* @param contextFactory the context factory to decorate
|
||||
* @return an updated supplier that will set the {@link MockServletContext}
|
||||
*/
|
||||
public static Supplier<ConfigurableWebApplicationContext> withMockServletContext(
|
||||
Supplier<ConfigurableWebApplicationContext> contextFactory) {
|
||||
@Contract("!null -> !null")
|
||||
public static @Nullable Supplier<ConfigurableWebApplicationContext> withMockServletContext(
|
||||
@Nullable Supplier<ConfigurableWebApplicationContext> contextFactory) {
|
||||
return (contextFactory != null) ? () -> {
|
||||
ConfigurableWebApplicationContext context = contextFactory.get();
|
||||
context.setServletContext(new MockServletContext());
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Test utilities to run application contexts for testing.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.context.runner;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+21
-8
@@ -27,6 +27,7 @@ import java.io.StringReader;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -68,9 +69,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public abstract class AbstractJsonMarshalTester<T> {
|
||||
|
||||
private Class<?> resourceLoadClass;
|
||||
private @Nullable Class<?> resourceLoadClass;
|
||||
|
||||
private ResolvableType type;
|
||||
private @Nullable ResolvableType type;
|
||||
|
||||
/**
|
||||
* Create a new uninitialized {@link AbstractJsonMarshalTester} instance.
|
||||
@@ -107,18 +108,30 @@ public abstract class AbstractJsonMarshalTester<T> {
|
||||
* Return the type under test.
|
||||
* @return the type under test
|
||||
*/
|
||||
protected final ResolvableType getType() {
|
||||
protected final @Nullable ResolvableType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
private ResolvableType getTypeNotNull() {
|
||||
ResolvableType type = getType();
|
||||
Assert.state(type != null, "Instance has not been initialized");
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return class used to load relative resources.
|
||||
* @return the resource load class
|
||||
*/
|
||||
protected final Class<?> getResourceLoadClass() {
|
||||
protected final @Nullable Class<?> getResourceLoadClass() {
|
||||
return this.resourceLoadClass;
|
||||
}
|
||||
|
||||
private Class<?> getResourceLoadClassNotNull() {
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
Assert.state(resourceLoadClass != null, "Instance has not been initialized");
|
||||
return resourceLoadClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link JsonContent} from writing the specific value.
|
||||
* @param value the value to write
|
||||
@@ -128,7 +141,7 @@ public abstract class AbstractJsonMarshalTester<T> {
|
||||
public JsonContent<T> write(T value) throws IOException {
|
||||
verify();
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
String json = writeObject(value, this.type);
|
||||
String json = writeObject(value, getTypeNotNull());
|
||||
return getJsonContent(json);
|
||||
}
|
||||
|
||||
@@ -140,7 +153,7 @@ public abstract class AbstractJsonMarshalTester<T> {
|
||||
* @since 2.1.5
|
||||
*/
|
||||
protected JsonContent<T> getJsonContent(String json) {
|
||||
return new JsonContent<>(getResourceLoadClass(), getType(), json);
|
||||
return new JsonContent<>(getResourceLoadClassNotNull(), getType(), json);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,7 +294,7 @@ public abstract class AbstractJsonMarshalTester<T> {
|
||||
verify();
|
||||
Assert.notNull(resource, "'resource' must not be null");
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
T object = readObject(inputStream, this.type);
|
||||
T object = readObject(inputStream, getTypeNotNull());
|
||||
closeQuietly(inputStream);
|
||||
return new ObjectContent<>(this.type, object);
|
||||
}
|
||||
@@ -306,7 +319,7 @@ public abstract class AbstractJsonMarshalTester<T> {
|
||||
public ObjectContent<T> read(Reader reader) throws IOException {
|
||||
verify();
|
||||
Assert.notNull(reader, "'reader' must not be null");
|
||||
T object = readObject(reader, this.type);
|
||||
T object = readObject(reader, getTypeNotNull());
|
||||
closeQuietly(reader);
|
||||
return new ObjectContent<>(this.type, object);
|
||||
}
|
||||
|
||||
+21
-18
@@ -20,6 +20,8 @@ import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -47,7 +49,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class BasicJsonTester {
|
||||
|
||||
private JsonLoader loader;
|
||||
private @Nullable JsonLoader loader;
|
||||
|
||||
/**
|
||||
* Create a new uninitialized {@link BasicJsonTester} instance.
|
||||
@@ -69,7 +71,7 @@ public class BasicJsonTester {
|
||||
* @param charset the charset used to load resources
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public BasicJsonTester(Class<?> resourceLoadClass, Charset charset) {
|
||||
public BasicJsonTester(Class<?> resourceLoadClass, @Nullable Charset charset) {
|
||||
Assert.notNull(resourceLoadClass, "'resourceLoadClass' must not be null");
|
||||
this.loader = new JsonLoader(resourceLoadClass, charset);
|
||||
}
|
||||
@@ -91,7 +93,7 @@ public class BasicJsonTester {
|
||||
* @param charset the charset used when loading relative classpath resources
|
||||
* @since 1.4.1
|
||||
*/
|
||||
protected final void initialize(Class<?> resourceLoadClass, Charset charset) {
|
||||
protected final void initialize(Class<?> resourceLoadClass, @Nullable Charset charset) {
|
||||
if (this.loader == null) {
|
||||
this.loader = new JsonLoader(resourceLoadClass, charset);
|
||||
}
|
||||
@@ -105,8 +107,8 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(CharSequence source) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,8 +118,8 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(String path, Class<?> resourceLoadClass) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(path, resourceLoadClass));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(path, resourceLoadClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,8 +128,8 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(byte[] source) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,8 +138,8 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(File source) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +148,8 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(InputStream source) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,16 +158,17 @@ public class BasicJsonTester {
|
||||
* @return the JSON content
|
||||
*/
|
||||
public JsonContent<Object> from(Resource source) {
|
||||
verify();
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
JsonLoader loader = verify();
|
||||
return getJsonContent(loader, loader.getJson(source));
|
||||
}
|
||||
|
||||
private void verify() {
|
||||
private JsonLoader verify() {
|
||||
Assert.state(this.loader != null, "Uninitialized BasicJsonTester");
|
||||
return this.loader;
|
||||
}
|
||||
|
||||
private JsonContent<Object> getJsonContent(String json) {
|
||||
return new JsonContent<>(this.loader.getResourceLoadClass(), null, json);
|
||||
private JsonContent<Object> getJsonContent(JsonLoader loader, String json) {
|
||||
return new JsonContent<>(loader.getResourceLoadClass(), null, json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-4
@@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
@@ -66,7 +67,7 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private Class<?> view;
|
||||
private @Nullable Class<?> view;
|
||||
|
||||
/**
|
||||
* Create a new {@link JacksonTester} instance.
|
||||
@@ -87,7 +88,8 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
this(resourceLoadClass, type, objectMapper, null);
|
||||
}
|
||||
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper, Class<?> view) {
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper,
|
||||
@Nullable Class<?> view) {
|
||||
super(resourceLoadClass, type);
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
@@ -100,7 +102,9 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
.jsonProvider(new JacksonJsonProvider(this.objectMapper))
|
||||
.mappingProvider(new JacksonMappingProvider(this.objectMapper))
|
||||
.build();
|
||||
return new JsonContent<>(getResourceLoadClass(), getType(), json, configuration);
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
return new JsonContent<>(resourceLoadClass, getType(), json, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -167,7 +171,11 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
* @return the new instance
|
||||
*/
|
||||
public JacksonTester<T> forView(Class<?> view) {
|
||||
return new JacksonTester<>(getResourceLoadClass(), getType(), this.objectMapper, view);
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
ResolvableType type = getType();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
Assert.state(type != null, "'type' must not be null");
|
||||
return new JacksonTester<>(resourceLoadClass, type, this.objectMapper, view);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-3
@@ -18,6 +18,7 @@ package org.springframework.boot.test.json;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -36,7 +37,7 @@ public final class JsonContent<T> implements AssertProvider<JsonContentAssert> {
|
||||
|
||||
private final Class<?> resourceLoadClass;
|
||||
|
||||
private final ResolvableType type;
|
||||
private final @Nullable ResolvableType type;
|
||||
|
||||
private final String json;
|
||||
|
||||
@@ -48,7 +49,7 @@ public final class JsonContent<T> implements AssertProvider<JsonContentAssert> {
|
||||
* @param type the type under test (or {@code null} if not known)
|
||||
* @param json the actual JSON content
|
||||
*/
|
||||
public JsonContent(Class<?> resourceLoadClass, ResolvableType type, String json) {
|
||||
public JsonContent(Class<?> resourceLoadClass, @Nullable ResolvableType type, String json) {
|
||||
this(resourceLoadClass, type, json, Configuration.defaultConfiguration());
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ public final class JsonContent<T> implements AssertProvider<JsonContentAssert> {
|
||||
* @param json the actual JSON content
|
||||
* @param configuration the JsonPath configuration
|
||||
*/
|
||||
JsonContent(Class<?> resourceLoadClass, ResolvableType type, String json, Configuration configuration) {
|
||||
JsonContent(Class<?> resourceLoadClass, @Nullable ResolvableType type, String json, Configuration configuration) {
|
||||
Assert.notNull(resourceLoadClass, "'resourceLoadClass' must not be null");
|
||||
Assert.notNull(json, "'json' must not be null");
|
||||
Assert.notNull(configuration, "'configuration' must not be null");
|
||||
|
||||
+16
-14
@@ -33,6 +33,7 @@ import org.assertj.core.api.Assert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.ListAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.skyscreamer.jsonassert.JSONCompare;
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode;
|
||||
import org.skyscreamer.jsonassert.JSONCompareResult;
|
||||
@@ -74,7 +75,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @param json the actual JSON content
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public JsonContentAssert(Class<?> resourceLoadClass, Charset charset, CharSequence json) {
|
||||
public JsonContentAssert(Class<?> resourceLoadClass, @Nullable Charset charset, CharSequence json) {
|
||||
this(resourceLoadClass, charset, json, Configuration.defaultConfiguration());
|
||||
}
|
||||
|
||||
@@ -86,7 +87,8 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @param json the actual JSON content
|
||||
* @param configuration the json-path configuration
|
||||
*/
|
||||
JsonContentAssert(Class<?> resourceLoadClass, Charset charset, CharSequence json, Configuration configuration) {
|
||||
JsonContentAssert(Class<?> resourceLoadClass, @Nullable Charset charset, CharSequence json,
|
||||
Configuration configuration) {
|
||||
super(json, JsonContentAssert.class);
|
||||
this.configuration = configuration;
|
||||
this.loader = new JsonLoader(resourceLoadClass, charset);
|
||||
@@ -98,7 +100,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public JsonContentAssert isEqualTo(Object expected) {
|
||||
public JsonContentAssert isEqualTo(@Nullable Object expected) {
|
||||
if (expected == null || expected instanceof CharSequence) {
|
||||
return isEqualToJson((CharSequence) expected);
|
||||
}
|
||||
@@ -115,7 +117,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
return isEqualToJson(resource);
|
||||
}
|
||||
failWithMessage("Unsupported type for JSON assert %s", expected.getClass());
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +130,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @return {@code this} assertion object
|
||||
* @throws AssertionError if the actual JSON value is not equal to the given one
|
||||
*/
|
||||
public JsonContentAssert isEqualToJson(CharSequence expected) {
|
||||
public JsonContentAssert isEqualToJson(@Nullable CharSequence expected) {
|
||||
String expectedJson = this.loader.getJson(expected);
|
||||
return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));
|
||||
}
|
||||
@@ -426,7 +428,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public JsonContentAssert isNotEqualTo(Object expected) {
|
||||
public JsonContentAssert isNotEqualTo(@Nullable Object expected) {
|
||||
if (expected == null || expected instanceof CharSequence) {
|
||||
return isNotEqualToJson((CharSequence) expected);
|
||||
}
|
||||
@@ -443,7 +445,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
return isNotEqualToJson(resource);
|
||||
}
|
||||
failWithMessage("Unsupported type for JSON assert %s", expected.getClass());
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,7 +458,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
* @return {@code this} assertion object
|
||||
* @throws AssertionError if the actual JSON value is equal to the given one
|
||||
*/
|
||||
public JsonContentAssert isNotEqualToJson(CharSequence expected) {
|
||||
public JsonContentAssert isNotEqualToJson(@Nullable CharSequence expected) {
|
||||
String expectedJson = this.loader.getJson(expected);
|
||||
return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));
|
||||
}
|
||||
@@ -985,7 +987,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T extractingJsonPathValue(CharSequence expression, Object[] args, Class<T> type,
|
||||
private <T> @Nullable T extractingJsonPathValue(CharSequence expression, Object[] args, Class<T> type,
|
||||
String expectedDescription) {
|
||||
JsonPathValue value = new JsonPathValue(expression, args);
|
||||
if (value.getValue(false) != null) {
|
||||
@@ -994,7 +996,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
return (T) value.getValue(false);
|
||||
}
|
||||
|
||||
private JSONCompareResult compare(CharSequence expectedJson, JSONCompareMode compareMode) {
|
||||
private JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONCompareMode compareMode) {
|
||||
if (this.actual == null) {
|
||||
return compareForNull(expectedJson);
|
||||
}
|
||||
@@ -1010,7 +1012,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
}
|
||||
}
|
||||
|
||||
private JSONCompareResult compare(CharSequence expectedJson, JSONComparator comparator) {
|
||||
private JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONComparator comparator) {
|
||||
if (this.actual == null) {
|
||||
return compareForNull(expectedJson);
|
||||
}
|
||||
@@ -1026,7 +1028,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
}
|
||||
}
|
||||
|
||||
private JSONCompareResult compareForNull(CharSequence expectedJson) {
|
||||
private JSONCompareResult compareForNull(@Nullable CharSequence expectedJson) {
|
||||
JSONCompareResult result = new JSONCompareResult();
|
||||
result.passed();
|
||||
if (expectedJson != null) {
|
||||
@@ -1099,7 +1101,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
}
|
||||
}
|
||||
|
||||
void assertHasValue(Class<?> type, String expectedDescription) {
|
||||
void assertHasValue(@Nullable Class<?> type, String expectedDescription) {
|
||||
Object value = getValue(true);
|
||||
if (value == null || isIndefiniteAndEmpty()) {
|
||||
failWithNoValueMessage();
|
||||
@@ -1128,7 +1130,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
|
||||
return ObjectUtils.isEmpty(getValue(false));
|
||||
}
|
||||
|
||||
Object getValue(boolean required) {
|
||||
@Nullable Object getValue(boolean required) {
|
||||
try {
|
||||
return read();
|
||||
}
|
||||
|
||||
+6
-2
@@ -25,8 +25,11 @@ import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
@@ -41,7 +44,7 @@ class JsonLoader {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
JsonLoader(Class<?> resourceLoadClass, Charset charset) {
|
||||
JsonLoader(Class<?> resourceLoadClass, @Nullable Charset charset) {
|
||||
this.resourceLoadClass = resourceLoadClass;
|
||||
this.charset = (charset != null) ? charset : StandardCharsets.UTF_8;
|
||||
}
|
||||
@@ -50,7 +53,8 @@ class JsonLoader {
|
||||
return this.resourceLoadClass;
|
||||
}
|
||||
|
||||
String getJson(CharSequence source) {
|
||||
@Contract("!null -> !null")
|
||||
@Nullable String getJson(@Nullable CharSequence source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.test.json;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -32,7 +33,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public final class ObjectContent<T> implements AssertProvider<ObjectContentAssert<T>> {
|
||||
|
||||
private final ResolvableType type;
|
||||
private final @Nullable ResolvableType type;
|
||||
|
||||
private final T object;
|
||||
|
||||
@@ -41,7 +42,7 @@ public final class ObjectContent<T> implements AssertProvider<ObjectContentAsser
|
||||
* @param type the type under test (or {@code null} if not known)
|
||||
* @param object the actual object content
|
||||
*/
|
||||
public ObjectContent(ResolvableType type, T object) {
|
||||
public ObjectContent(@Nullable ResolvableType type, T object) {
|
||||
Assert.notNull(object, "'object' must not be null");
|
||||
this.type = type;
|
||||
this.object = object;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Support for testing JSON.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.json;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+4
-2
@@ -22,6 +22,8 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.io.FileSystemResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -42,7 +44,7 @@ public class SpringBootMockServletContext extends MockServletContext {
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private File emptyRootDirectory;
|
||||
private @Nullable File emptyRootDirectory;
|
||||
|
||||
public SpringBootMockServletContext(String resourceBasePath) {
|
||||
this(resourceBasePath, new FileSystemResourceLoader());
|
||||
@@ -86,7 +88,7 @@ public class SpringBootMockServletContext extends MockServletContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String path) throws MalformedURLException {
|
||||
public @Nullable URL getResource(String path) throws MalformedURLException {
|
||||
URL resource = super.getResource(path);
|
||||
if (resource == null && "/".equals(path)) {
|
||||
// Liquibase assumes that "/" always exists, if we don't have a directory
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Mock web classes specific to Spring Boot.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.mock.web;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* RSocket server test utilities and support classes.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.rsocket.server;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+4
-2
@@ -27,6 +27,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.ansi.AnsiOutput;
|
||||
import org.springframework.boot.ansi.AnsiOutput.Enabled;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -47,7 +49,7 @@ class OutputCapture implements CapturedOutput {
|
||||
|
||||
private final Deque<SystemCapture> systemCaptures = new ArrayDeque<>();
|
||||
|
||||
private AnsiOutputState ansiOutputState;
|
||||
private @Nullable AnsiOutputState ansiOutputState;
|
||||
|
||||
private final AtomicReference<String> out = new AtomicReference<>(null);
|
||||
|
||||
@@ -329,7 +331,7 @@ class OutputCapture implements CapturedOutput {
|
||||
AnsiOutput.setEnabled(this.saved);
|
||||
}
|
||||
|
||||
static AnsiOutputState saveAndDisable() {
|
||||
static @Nullable AnsiOutputState saveAndDisable() {
|
||||
if (!ClassUtils.isPresent("org.springframework.boot.ansi.AnsiOutput",
|
||||
OutputCapture.class.getClassLoader())) {
|
||||
return null;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Classes for {@link java.lang.System System}-related testing.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.system;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.test.util;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
@@ -31,7 +33,7 @@ public abstract class ApplicationContextTestUtils {
|
||||
* Closes this {@link ApplicationContext} and its parent hierarchy if any.
|
||||
* @param context the context to close (can be {@code null})
|
||||
*/
|
||||
public static void closeAll(ApplicationContext context) {
|
||||
public static void closeAll(@Nullable ApplicationContext context) {
|
||||
if (context != null) {
|
||||
if (context instanceof ConfigurableApplicationContext configurableContext) {
|
||||
configurableContext.close();
|
||||
|
||||
+22
-18
@@ -27,6 +27,8 @@ import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -37,6 +39,7 @@ import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.env.SystemEnvironmentPropertySource;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -76,7 +79,7 @@ public final class TestPropertyValues {
|
||||
* @return a new {@link TestPropertyValues} instance
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public TestPropertyValues and(Iterable<String> pairs) {
|
||||
public TestPropertyValues and(@Nullable Iterable<String> pairs) {
|
||||
return (pairs != null) ? and(StreamSupport.stream(pairs.spliterator(), false)) : this;
|
||||
}
|
||||
|
||||
@@ -87,7 +90,7 @@ public final class TestPropertyValues {
|
||||
* @return a new {@link TestPropertyValues} instance
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public TestPropertyValues and(Stream<String> pairs) {
|
||||
public TestPropertyValues and(@Nullable Stream<String> pairs) {
|
||||
return (pairs != null) ? and(pairs, Pair::parse) : this;
|
||||
}
|
||||
|
||||
@@ -97,7 +100,7 @@ public final class TestPropertyValues {
|
||||
* @return a new {@link TestPropertyValues} instance
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public TestPropertyValues and(Map<String, String> map) {
|
||||
public TestPropertyValues and(@Nullable Map<String, String> map) {
|
||||
return (map != null) ? and(map.entrySet().stream(), Pair::fromMapEntry) : this;
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@ public final class TestPropertyValues {
|
||||
* @return a new {@link TestPropertyValues} instance
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public <T> TestPropertyValues and(Stream<T> stream, Function<T, Pair> mapper) {
|
||||
public <T> TestPropertyValues and(@Nullable Stream<T> stream, Function<T, @Nullable Pair> mapper) {
|
||||
if (stream == null) {
|
||||
return this;
|
||||
}
|
||||
@@ -200,8 +203,8 @@ public final class TestPropertyValues {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addToSources(MutablePropertySources sources, Type type, String name) {
|
||||
if (sources.contains(name)) {
|
||||
PropertySource<?> propertySource = sources.get(name);
|
||||
PropertySource<?> propertySource = sources.get(name);
|
||||
if (propertySource != null) {
|
||||
if (propertySource.getClass() == type.getSourceClass()) {
|
||||
((Map<String, Object>) propertySource.getSource()).putAll(this.properties);
|
||||
return;
|
||||
@@ -232,7 +235,7 @@ public final class TestPropertyValues {
|
||||
* environment
|
||||
* @return the new instance
|
||||
*/
|
||||
public static TestPropertyValues of(Iterable<String> pairs) {
|
||||
public static TestPropertyValues of(@Nullable Iterable<String> pairs) {
|
||||
return (pairs != null) ? of(StreamSupport.stream(pairs.spliterator(), false)) : empty();
|
||||
}
|
||||
|
||||
@@ -244,7 +247,7 @@ public final class TestPropertyValues {
|
||||
* environment
|
||||
* @return the new instance
|
||||
*/
|
||||
public static TestPropertyValues of(Stream<String> pairs) {
|
||||
public static TestPropertyValues of(@Nullable Stream<String> pairs) {
|
||||
return (pairs != null) ? of(pairs, Pair::parse) : empty();
|
||||
}
|
||||
|
||||
@@ -254,7 +257,7 @@ public final class TestPropertyValues {
|
||||
* @param map the map of properties that need to be added to the environment
|
||||
* @return the new instance
|
||||
*/
|
||||
public static TestPropertyValues of(Map<String, String> map) {
|
||||
public static TestPropertyValues of(@Nullable Map<String, String> map) {
|
||||
return (map != null) ? of(map.entrySet().stream(), Pair::fromMapEntry) : empty();
|
||||
}
|
||||
|
||||
@@ -267,7 +270,7 @@ public final class TestPropertyValues {
|
||||
* {@link Pair}
|
||||
* @return the new instance
|
||||
*/
|
||||
public static <T> TestPropertyValues of(Stream<T> stream, Function<T, Pair> mapper) {
|
||||
public static <T> TestPropertyValues of(@Nullable Stream<T> stream, Function<T, @Nullable Pair> mapper) {
|
||||
return (stream != null) ? empty().and(stream, mapper) : empty();
|
||||
}
|
||||
|
||||
@@ -297,9 +300,9 @@ public final class TestPropertyValues {
|
||||
|
||||
private final Class<? extends MapPropertySource> sourceClass;
|
||||
|
||||
private final String suffix;
|
||||
private final @Nullable String suffix;
|
||||
|
||||
Type(Class<? extends MapPropertySource> sourceClass, String suffix) {
|
||||
Type(Class<? extends MapPropertySource> sourceClass, @Nullable String suffix) {
|
||||
this.sourceClass = sourceClass;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
@@ -321,9 +324,9 @@ public final class TestPropertyValues {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String value;
|
||||
private final @Nullable String value;
|
||||
|
||||
private Pair(String name, String value) {
|
||||
private Pair(String name, @Nullable String value) {
|
||||
Assert.hasLength(name, "'name' must not be empty");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
@@ -333,7 +336,7 @@ public final class TestPropertyValues {
|
||||
properties.put(this.name, this.value);
|
||||
}
|
||||
|
||||
public static Pair parse(String pair) {
|
||||
public static @Nullable Pair parse(String pair) {
|
||||
int index = getSeparatorIndex(pair);
|
||||
String name = (index > 0) ? pair.substring(0, index) : pair;
|
||||
String value = (index > 0) ? pair.substring(index + 1) : "";
|
||||
@@ -358,7 +361,8 @@ public final class TestPropertyValues {
|
||||
* @return the {@link Pair} instance or {@code null}
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static Pair fromMapEntry(Map.Entry<String, String> entry) {
|
||||
@Contract("!null -> !null")
|
||||
public static @Nullable Pair fromMapEntry(Map.@Nullable Entry<String, String> entry) {
|
||||
return (entry != null) ? of(entry.getKey(), entry.getValue()) : null;
|
||||
}
|
||||
|
||||
@@ -369,8 +373,8 @@ public final class TestPropertyValues {
|
||||
* @return the {@link Pair} instance or {@code null}
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static Pair of(String name, String value) {
|
||||
if (StringUtils.hasLength(name) || StringUtils.hasLength(value)) {
|
||||
public static @Nullable Pair of(@Nullable String name, @Nullable String value) {
|
||||
if (StringUtils.hasLength(name)) {
|
||||
return new Pair(name, value);
|
||||
}
|
||||
return null;
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* General purpose test utilities.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.test.util;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
Reference in New Issue
Block a user