diff --git a/core/spring-boot/build.gradle b/core/spring-boot/build.gradle index 01010c00564..5b6c9fb4ab5 100644 --- a/core/spring-boot/build.gradle +++ b/core/spring-boot/build.gradle @@ -50,6 +50,8 @@ dependencies { optional("org.yaml:snakeyaml") optional("tools.jackson.core:jackson-databind") + testCompileOnly("com.google.code.findbugs:jsr305") + testFixturesCompileOnly(project(":test-support:spring-boot-test-support")) testImplementation(project(":test-support:spring-boot-test-support")) @@ -106,3 +108,7 @@ sourceSets { } } } + +tasks.named("compileTestJava") { + options.nullability.checking = "tests" +} diff --git a/core/spring-boot/src/test/java/org/springframework/boot/BannerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/BannerTests.java index 6e868cddeae..d9e458435ad 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/BannerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/BannerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot; import java.io.PrintStream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -49,7 +50,7 @@ import static org.mockito.Mockito.reset; @ExtendWith({ MockitoExtension.class, OutputCaptureExtension.class }) class BannerTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @AfterEach void cleanUp() { @@ -59,6 +60,7 @@ class BannerTests { } @Captor + @SuppressWarnings("NullAway.Init") private ArgumentCaptor> sourceClassCaptor; @Test @@ -123,7 +125,7 @@ class BannerTests { static class DummyBanner implements Banner { @Override - public void printBanner(Environment environment, Class sourceClass, PrintStream out) { + public void printBanner(Environment environment, @Nullable Class sourceClass, PrintStream out) { out.println("My Banner"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/DefaultApplicationArgumentsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/DefaultApplicationArgumentsTests.java index 14c442c37fa..0c8327e7f2e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/DefaultApplicationArgumentsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/DefaultApplicationArgumentsTests.java @@ -35,6 +35,7 @@ class DefaultApplicationArgumentsTests { private static final String[] ARGS = new String[] { "--foo=bar", "--foo=baz", "--debug", "spring", "boot" }; @Test + @SuppressWarnings("NullAway") // Test null check void argumentsMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new DefaultApplicationArguments((String[]) null)) .withMessageContaining("'args' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java index 199e9120e5c..662607cbbe5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java @@ -37,6 +37,7 @@ import static org.mockito.Mockito.withSettings; class ExitCodeGeneratorsTests { @Test + @SuppressWarnings("NullAway") // Test null check void addAllWhenGeneratorsIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> { List generators = null; @@ -45,6 +46,7 @@ class ExitCodeGeneratorsTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addWhenGeneratorIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ExitCodeGenerators().add(null)) .withMessageContaining("'generator' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/MockApplicationEnvironment.java b/core/spring-boot/src/test/java/org/springframework/boot/MockApplicationEnvironment.java index 6bb22e29f29..b1647f2caa0 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/MockApplicationEnvironment.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/MockApplicationEnvironment.java @@ -16,6 +16,8 @@ package org.springframework.boot; +import org.jspecify.annotations.Nullable; + import org.springframework.mock.env.MockEnvironment; /** @@ -27,12 +29,12 @@ import org.springframework.mock.env.MockEnvironment; public class MockApplicationEnvironment extends MockEnvironment { @Override - protected String doGetActiveProfilesProperty() { + protected @Nullable String doGetActiveProfilesProperty() { return null; } @Override - protected String doGetDefaultProfilesProperty() { + protected @Nullable String doGetDefaultProfilesProperty() { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java index e3b6991150e..3cd207cd2a9 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java @@ -16,6 +16,7 @@ package org.springframework.boot; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -35,7 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ class OverrideSourcesTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @AfterEach void cleanUp() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java index 5f0055c0251..ff9e4c1db51 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -170,12 +171,12 @@ class ResourceBannerTests { assertThat(banner).startsWith("banner bar"); } - private String printBanner(Resource resource, String bootVersion, String applicationVersion, - String applicationTitle) { + private String printBanner(Resource resource, @Nullable String bootVersion, @Nullable String applicationVersion, + @Nullable String applicationTitle) { return printBanner(new MockResourceBanner(resource, bootVersion, applicationTitle), applicationVersion); } - private String printBanner(ResourceBanner banner, String applicationVersion) { + private String printBanner(ResourceBanner banner, @Nullable String applicationVersion) { MockEnvironment environment = new MockEnvironment(); if (applicationVersion != null) { environment.setProperty("spring.application.version", applicationVersion); @@ -189,23 +190,23 @@ class ResourceBannerTests { static class MockResourceBanner extends ResourceBanner { - private final String bootVersion; + private final @Nullable String bootVersion; - private final String applicationTitle; + private final @Nullable String applicationTitle; - MockResourceBanner(Resource resource, String bootVersion, String applicationTitle) { + MockResourceBanner(Resource resource, @Nullable String bootVersion, @Nullable String applicationTitle) { super(resource); this.bootVersion = bootVersion; this.applicationTitle = applicationTitle; } @Override - protected String getBootVersion() { + protected @Nullable String getBootVersion() { return this.bootVersion; } @Override - protected String getApplicationTitle(Class sourceClass) { + protected @Nullable String getApplicationTitle(@Nullable Class sourceClass) { return this.applicationTitle; } @@ -213,23 +214,23 @@ class ResourceBannerTests { static class MutatingResourceBanner extends MockResourceBanner { - MutatingResourceBanner(Resource resource, String bootVersion, String applicationTitle) { + MutatingResourceBanner(Resource resource, String bootVersion, @Nullable String applicationTitle) { super(resource, bootVersion, applicationTitle); } @Override - protected List getPropertyResolvers(Environment environment, Class sourceClass) { + protected List getPropertyResolvers(Environment environment, @Nullable Class sourceClass) { List resolvers = super.getPropertyResolvers(environment, sourceClass); PropertyResolver resolver = new AbstractPropertyResolver() { @Override @SuppressWarnings("unchecked") - public T getProperty(String key, Class targetType) { + public @Nullable T getProperty(String key, Class targetType) { return String.class.equals(targetType) ? (T) getPropertyAsRawString(key) : null; } @Override - protected String getPropertyAsRawString(String key) { + protected @Nullable String getPropertyAsRawString(String key) { return ("foo".equals(key)) ? "bar" : null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java index f75afeeead0..a852f34da67 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java @@ -18,6 +18,7 @@ package org.springframework.boot; import java.nio.file.Path; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -101,7 +102,7 @@ class SpringApplicationAotProcessorTests { @Configuration(proxyBeanMethods = false) public static class SampleApplication { - public static String[] argsHolder; + public static String @Nullable [] argsHolder; public static boolean postRunInvoked; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java index 348a3ad7369..327b44e6469 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java @@ -25,6 +25,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.awaitility.Awaitility; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mockito.InOrder; @@ -152,6 +153,7 @@ class SpringApplicationShutdownHookTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addHandlerActionWhenNullThrowsException() { TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); assertThatIllegalArgumentException().isThrownBy(() -> shutdownHook.getHandlers().add(null)) @@ -168,6 +170,7 @@ class SpringApplicationShutdownHookTests { } @Test + @SuppressWarnings("NullAway") // Test null check void removeHandlerActionWhenNullThrowsException() { TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); assertThatIllegalArgumentException().isThrownBy(() -> shutdownHook.getHandlers().remove(null)) @@ -244,15 +247,16 @@ class SpringApplicationShutdownHookTests { private final List finished; - private final CountDownLatch closing; + private final @Nullable CountDownLatch closing; - private final CountDownLatch proceedWithClose; + private final @Nullable CountDownLatch proceedWithClose; TestApplicationContext(List finished) { this(finished, null, null); } - TestApplicationContext(List finished, CountDownLatch closing, CountDownLatch proceedWithClose) { + TestApplicationContext(List finished, @Nullable CountDownLatch closing, + @Nullable CountDownLatch proceedWithClose) { this.finished = finished; this.closing = closing; this.proceedWithClose = proceedWithClose; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index e709b60335e..1fd1b800487 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -32,6 +33,7 @@ import java.util.function.Supplier; import jakarta.annotation.PostConstruct; import org.assertj.core.api.Condition; import org.awaitility.Awaitility; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -167,7 +169,7 @@ class SpringApplicationTests { private String headlessProperty; - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; private Environment getEnvironment() { if (this.context != null) { @@ -202,6 +204,8 @@ class SpringApplicationTests { } @Test + @SuppressWarnings("NullAway") + // Test null check void sourcesMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new SpringApplication((Class[]) null).run()) .withMessageContaining("'primarySources' must not be null"); @@ -360,7 +364,9 @@ class SpringApplicationTests { application.setWebApplicationType(WebApplicationType.NONE); AtomicReference reference = addListener(application, ApplicationReadyEvent.class); this.context = application.run("--foo=bar"); - assertThat(application).isSameAs(reference.get().getSpringApplication()); + ApplicationReadyEvent event = reference.get(); + assertThat(event).isNotNull(); + assertThat(application).isSameAs(event.getSpringApplication()); } @Test @@ -369,7 +375,9 @@ class SpringApplicationTests { application.setWebApplicationType(WebApplicationType.NONE); AtomicReference reference = addListener(application, ContextRefreshedEvent.class); this.context = application.run("--foo=bar"); - assertThat(this.context).isSameAs(reference.get().getApplicationContext()); + ContextRefreshedEvent event = reference.get(); + assertThat(event).isNotNull(); + assertThat(this.context).isSameAs(event.getApplicationContext()); // Custom initializers do not switch off the defaults assertThat(getEnvironment().getProperty("foo")).isEqualTo("bar"); } @@ -487,6 +495,7 @@ class SpringApplicationTests { assertThat(environment.getProperty("foo")).isEqualTo("bar"); CompositePropertySource composite = (CompositePropertySource) environment.getPropertySources() .get("commandLineArgs"); + assertThat(composite).isNotNull(); assertThat(composite.getPropertySources()).hasSize(2); assertThat(composite.getPropertySources()).first() .matches((source) -> source.getName().equals("springApplicationCommandLineArgs"), @@ -878,8 +887,9 @@ class SpringApplicationTests { @Test void defaultCommandLineArgs() { SpringApplication application = new SpringApplication(ExampleConfig.class); - application.setDefaultProperties( - StringUtils.splitArrayElementsIntoProperties(new String[] { "baz=", "bar=spam" }, "=")); + Properties properties = StringUtils.splitArrayElementsIntoProperties(new String[] { "baz=", "bar=spam" }, "="); + assertThat(properties).isNotNull(); + application.setDefaultProperties(properties); application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--bar=foo", "bucket", "crap"); assertThat(this.context).isInstanceOf(AnnotationConfigApplicationContext.class); @@ -936,7 +946,7 @@ class SpringApplicationTests { this.context = application.run(); assertThat(events).hasAtLeastOneElementOfType(ApplicationPreparedEvent.class); assertThat(events).hasAtLeastOneElementOfType(ContextRefreshedEvent.class); - verifyRegisteredListenerSuccessEvents(); + verifyRegisteredListenerSuccessEvents(this.context); } @Test @@ -949,12 +959,12 @@ class SpringApplicationTests { this.context = application.run(); assertThat(events).hasAtLeastOneElementOfType(ApplicationPreparedEvent.class); assertThat(events).hasAtLeastOneElementOfType(ContextRefreshedEvent.class); - verifyRegisteredListenerSuccessEvents(); + verifyRegisteredListenerSuccessEvents(this.context); } @SuppressWarnings("unchecked") - private void verifyRegisteredListenerSuccessEvents() { - ApplicationListener listener = this.context.getBean("testApplicationListener", + private void verifyRegisteredListenerSuccessEvents(ConfigurableApplicationContext context) { + ApplicationListener listener = context.getBean("testApplicationListener", ApplicationListener.class); InOrder inOrder = Mockito.inOrder(listener); then(listener).should(inOrder).onApplicationEvent(isA(ContextRefreshedEvent.class)); @@ -1224,9 +1234,11 @@ class SpringApplicationTests { application.setWebApplicationType(WebApplicationType.NONE); application.addBootstrapRegistryInitializer((bootstrapContext) -> { bootstrapContext.register(String.class, InstanceSupplier.of("boot")); - bootstrapContext.addCloseListener((event) -> event.getApplicationContext() - .getBeanFactory() - .registerSingleton("test", event.getBootstrapContext().get(String.class))); + bootstrapContext.addCloseListener((event) -> { + String string = event.getBootstrapContext().get(String.class); + assertThat(string).isNotNull(); + event.getApplicationContext().getBeanFactory().registerSingleton("test", string); + }); }); ConfigurableApplicationContext applicationContext = application.run(); assertThat(applicationContext.getBean("test")).isEqualTo("boot"); @@ -1272,8 +1284,9 @@ class SpringApplicationTests { .map(ApplicationFailedEvent.class::cast) .findFirst() .get(); - assertThat(SpringApplicationShutdownHookInstance.get()) - .didNotRegisterApplicationContext(failure.getApplicationContext()); + ConfigurableApplicationContext context = failure.getApplicationContext(); + assertThat(context).isNotNull(); + assertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(context); } @Test @@ -1283,6 +1296,7 @@ class SpringApplicationTests { SpringApplicationRunListener runListener = mock(SpringApplicationRunListener.class); SpringApplicationHook hook = (springApplication) -> runListener; SpringApplication.withHook(hook, () -> this.context = application.run()); + assertThat(this.context).isNotNull(); then(runListener).should().starting(any()); then(runListener).should().contextPrepared(this.context); then(runListener).should().ready(eq(this.context), any()); @@ -1320,7 +1334,11 @@ class SpringApplicationTests { SpringApplicationHook hook = (springApplication) -> runListener; assertThatExceptionOfType(SpringApplication.AbandonedRunException.class) .isThrownBy(() -> SpringApplication.withHook(hook, () -> application.run())) - .satisfies((ex) -> assertThat(ex.getApplicationContext().isRunning()).isFalse()); + .satisfies((ex) -> { + ConfigurableApplicationContext context = ex.getApplicationContext(); + assertThat(context).isNotNull(); + assertThat(context.isRunning()).isFalse(); + }); then(runListener).should().starting(any()); then(runListener).should().contextPrepared(any()); then(runListener).should(never()).ready(any(), any()); @@ -1389,7 +1407,10 @@ class SpringApplicationTests { .with(SingleUseAdditionalConfig.class) .run() .getApplicationContext(); - assertThatNoException().isThrownBy(() -> this.context.getBean(SingleUseAdditionalConfig.class)); + assertThatNoException().isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(SingleUseAdditionalConfig.class); + }); } @Test @@ -1540,7 +1561,7 @@ class SpringApplicationTests { static class TestSpringApplication extends SpringApplication { - private BeanDefinitionLoader loader; + private @Nullable BeanDefinitionLoader loader; private boolean useMockLoader; @@ -1567,7 +1588,7 @@ class SpringApplicationTests { return this.loader; } - BeanDefinitionLoader getLoader() { + @Nullable BeanDefinitionLoader getLoader() { return this.loader; } @@ -1855,6 +1876,7 @@ class SpringApplicationTests { private final String[] expectedBefore; + @SuppressWarnings("NullAway.Init") private ApplicationContext applicationContext; private final int order; @@ -1926,14 +1948,14 @@ class SpringApplicationTests { static class ExitCodeListener implements ApplicationListener { - private Integer exitCode; + private @Nullable Integer exitCode; @Override public void onApplicationEvent(ExitCodeEvent event) { this.exitCode = event.getExitCode(); } - Integer getExitCode() { + @Nullable Integer getExitCode() { return this.exitCode; } @@ -1971,7 +1993,9 @@ class SpringApplicationTests { @SuppressWarnings("unchecked") E getEvent(Class type) { - return (E) this.events.get(type).get(0); + List events = this.events.get(type); + assertThat(events).isNotNull(); + return (E) events.get(0); } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/StartupInfoLoggerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/StartupInfoLoggerTests.java index 1d86782a364..c8bca9f8937 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/StartupInfoLoggerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/StartupInfoLoggerTests.java @@ -17,6 +17,7 @@ package org.springframework.boot; import org.apache.commons.logging.Log; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -133,11 +134,11 @@ class StartupInfoLoggerTests { private final long startTime = System.currentTimeMillis(); - private final Long uptime; + private final @Nullable Long uptime; private final String action; - TestStartup(Long uptime, String action) { + TestStartup(@Nullable Long uptime, String action) { this.uptime = uptime; this.action = action; started(); @@ -149,7 +150,7 @@ class StartupInfoLoggerTests { } @Override - protected Long processUptime() { + protected @Nullable Long processUptime() { return this.uptime; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java b/core/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java index 55aa79829f2..0058306885f 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java @@ -24,6 +24,7 @@ import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,7 +55,7 @@ class SpringApplicationAdminMXBeanRegistrarTests { private MBeanServer mBeanServer; - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @BeforeEach void setup() { @@ -90,15 +91,18 @@ class SpringApplicationAdminMXBeanRegistrarTests { SpringApplicationAdminMXBeanRegistrar registrar = new SpringApplicationAdminMXBeanRegistrar(OBJECT_NAME); ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class); registrar.setApplicationContext(context); - registrar.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), null, + registrar.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], mock(ConfigurableApplicationContext.class), null)); assertThat(isApplicationReady(registrar)).isFalse(); - registrar.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), null, context, null)); + registrar + .onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context, null)); assertThat(isApplicationReady(registrar)).isTrue(); } private boolean isApplicationReady(SpringApplicationAdminMXBeanRegistrar registrar) { - return (Boolean) ReflectionTestUtils.getField(registrar, "ready"); + Object field = ReflectionTestUtils.getField(registrar, "ready"); + assertThat(field).isNotNull(); + return (Boolean) field; } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/availability/AvailabilityChangeEventTests.java b/core/spring-boot/src/test/java/org/springframework/boot/availability/AvailabilityChangeEventTests.java index 2c06ec0a340..3e3a190a6b2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/availability/AvailabilityChangeEventTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/availability/AvailabilityChangeEventTests.java @@ -40,6 +40,7 @@ class AvailabilityChangeEventTests { private final Object source = new Object(); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenStateIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new AvailabilityChangeEvent<>(this.source, null)) .withMessage("Payload must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/bootstrap/DefaultBootstrapContextTests.java b/core/spring-boot/src/test/java/org/springframework/boot/bootstrap/DefaultBootstrapContextTests.java index 509987bd292..a5807a2cf19 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/bootstrap/DefaultBootstrapContextTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/bootstrap/DefaultBootstrapContextTests.java @@ -18,9 +18,11 @@ package org.springframework.boot.bootstrap; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AssertProvider; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier; @@ -34,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIOException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.Mockito.mock; /** * Tests for {@link DefaultBootstrapContext}. @@ -49,12 +52,14 @@ class DefaultBootstrapContextTests { private final StaticApplicationContext applicationContext = new StaticApplicationContext(); @Test + @SuppressWarnings("NullAway") // Test null check void registerWhenTypeIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> this.context.register(null, InstanceSupplier.of(1))) .withMessage("'type' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void registerWhenRegistrationIsNullThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> this.context.register(Integer.class, null)) .withMessage("'instanceSupplier' must not be null"); @@ -206,20 +211,23 @@ class DefaultBootstrapContextTests { @Test void getOrElseSupplyWhenNoRegistrationReturnsSupplied() { this.context.register(Number.class, InstanceSupplier.of(1)); - assertThat(this.context.getOrElseSupply(Long.class, () -> -1L)).isEqualTo(-1); + Supplier<@Nullable Long> supplier = () -> -1L; + assertThat(this.context.getOrElseSupply(Long.class, supplier)).isEqualTo(-1); } @Test void getOrElseSupplyWhenRegisteredAsNullReturnsNull() { this.context.register(Number.class, InstanceSupplier.of(null)); - assertThat(this.context.getOrElseSupply(Number.class, () -> -1L)).isNull(); + Supplier<@Nullable Number> supplier = () -> -1L; + assertThat(this.context.getOrElseSupply(Number.class, supplier)).isNull(); } @Test void getOrElseSupplyCreatesOnlyOneInstance() { this.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement)); - assertThat(this.context.getOrElseSupply(Integer.class, () -> -1)).isZero(); - assertThat(this.context.getOrElseSupply(Integer.class, () -> -1)).isZero(); + Supplier<@Nullable Integer> supplier = () -> -1; + assertThat(this.context.getOrElseSupply(Integer.class, supplier)).isZero(); + assertThat(this.context.getOrElseSupply(Integer.class, supplier)).isZero(); } @Test @@ -265,14 +273,14 @@ class DefaultBootstrapContextTests { void instanceSupplierGetScopeWhenNotConfiguredReturnsSingleton() { InstanceSupplier supplier = InstanceSupplier.of("test"); assertThat(supplier.getScope()).isEqualTo(Scope.SINGLETON); - assertThat(supplier.get(null)).isEqualTo("test"); + assertThat(supplier.get(mock(BootstrapContext.class))).isEqualTo("test"); } @Test void instanceSupplierWithScopeChangesScope() { InstanceSupplier supplier = InstanceSupplier.of("test").withScope(Scope.PROTOTYPE); assertThat(supplier.getScope()).isEqualTo(Scope.PROTOTYPE); - assertThat(supplier.get(null)).isEqualTo("test"); + assertThat(supplier.get(mock(BootstrapContext.class))).isEqualTo("test"); } private static final class TestCloseListener @@ -280,9 +288,9 @@ class DefaultBootstrapContextTests { private int called; - private BootstrapContext bootstrapContext; + private @Nullable BootstrapContext bootstrapContext; - private ConfigurableApplicationContext applicationContext; + private @Nullable ConfigurableApplicationContext applicationContext; @Override public void onApplicationEvent(BootstrapContextClosedEvent event) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java index 3227adb7922..96913f3edb7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java @@ -19,8 +19,10 @@ package org.springframework.boot.builder; import java.net.URL; import java.net.URLClassLoader; import java.util.Collections; +import java.util.Properties; import org.assertj.core.api.InstanceOfAssertFactories; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -56,7 +58,7 @@ import static org.mockito.Mockito.spy; */ class SpringApplicationBuilderTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @AfterEach void close() { @@ -64,7 +66,7 @@ class SpringApplicationBuilderTests { SpringApplicationShutdownHookInstance.reset(); } - private void close(ApplicationContext context) { + private void close(@Nullable ApplicationContext context) { if (context != null) { if (context instanceof ConfigurableApplicationContext configurableContext) { configurableContext.close(); @@ -103,9 +105,11 @@ class SpringApplicationBuilderTests { @Test void propertiesAsProperties() { + Properties properties = StringUtils.splitArrayElementsIntoProperties(new String[] { "bar=foo" }, "="); + assertThat(properties).isNotNull(); SpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class) .contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class)) - .properties(StringUtils.splitArrayElementsIntoProperties(new String[] { "bar=foo" }, "=")); + .properties(properties); this.context = application.run(); assertThat(this.context.getEnvironment().getProperty("bar")).isEqualTo("foo"); } @@ -140,8 +144,9 @@ class SpringApplicationBuilderTests { then(((SpyApplicationContext) this.context).getApplicationContext()).should() .setParent(any(ApplicationContext.class)); assertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context); - assertThat(this.context.getParent().getBean(ApplicationArguments.class).getNonOptionArgs()) - .contains("foo.bar=baz"); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getBean(ApplicationArguments.class).getNonOptionArgs()).contains("foo.bar=baz"); assertThat(this.context.getBean(ApplicationArguments.class).getNonOptionArgs()).contains("foo.bar=baz"); } @@ -154,7 +159,9 @@ class SpringApplicationBuilderTests { then(((SpyApplicationContext) this.context).getApplicationContext()).should() .setParent(any(ApplicationContext.class)); assertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context); - assertThat(this.context.getParent().getBean(ApplicationArguments.class).getNonOptionArgs()).contains("a=alpha"); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getBean(ApplicationArguments.class).getNonOptionArgs()).contains("a=alpha"); assertThat(this.context.getBean(ApplicationArguments.class).getNonOptionArgs()).contains("b=bravo"); } @@ -188,7 +195,9 @@ class SpringApplicationBuilderTests { application.resourceLoader(new DefaultResourceLoader(classLoader)); application.parent(ExampleConfig.class); this.context = application.run(); - assertThat(((SpyApplicationContext) this.context).getResourceLoader().getClassLoader()).isEqualTo(classLoader); + ResourceLoader resourceLoader = ((SpyApplicationContext) this.context).getResourceLoader(); + assertThat(resourceLoader).isNotNull(); + assertThat(resourceLoader.getClassLoader()).isEqualTo(classLoader); } @Test @@ -212,8 +221,10 @@ class SpringApplicationBuilderTests { this.context = application.run(); assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node"))).isTrue(); assertThat(this.context.getEnvironment().getProperty("transport")).isEqualTo("redis"); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles(Profiles.of("node"))).isTrue(); - assertThat(this.context.getParent().getEnvironment().getProperty("transport")).isEqualTo("redis"); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getEnvironment().acceptsProfiles(Profiles.of("node"))).isTrue(); + assertThat(parent.getEnvironment().getProperty("transport")).isEqualTo("redis"); // only defined in node profile assertThat(this.context.getEnvironment().getProperty("bar")).isEqualTo("spam"); } @@ -227,7 +238,9 @@ class SpringApplicationBuilderTests { .web(WebApplicationType.NONE); this.context = application.run(); assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles(Profiles.of("admin"))).isFalse(); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getEnvironment().acceptsProfiles(Profiles.of("admin"))).isFalse(); } @Test @@ -240,8 +253,10 @@ class SpringApplicationBuilderTests { shared.profiles("parent"); this.context = application.run(); assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles(Profiles.of("node", "parent"))).isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles(Profiles.of("admin"))).isFalse(); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getEnvironment().acceptsProfiles(Profiles.of("node", "parent"))).isTrue(); + assertThat(parent.getEnvironment().acceptsProfiles(Profiles.of("admin"))).isFalse(); } @Test @@ -257,7 +272,9 @@ class SpringApplicationBuilderTests { assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); // Now they share an Environment explicitly so there's no way to keep the profiles // separate - assertThat(this.context.getParent().getEnvironment().acceptsProfiles(Profiles.of("admin"))).isTrue(); + ApplicationContext parent = this.context.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.getEnvironment().acceptsProfiles(Profiles.of("admin"))).isTrue(); } @Test @@ -330,7 +347,8 @@ class SpringApplicationBuilderTests { SpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(resourceLoader, ExampleConfig.class) { @Override - protected SpringApplication createSpringApplication(ResourceLoader resourceLoader, Class... sources) { + protected SpringApplication createSpringApplication(@Nullable ResourceLoader resourceLoader, + Class... sources) { return new CustomSpringApplication(resourceLoader, sources); } }; @@ -351,9 +369,9 @@ class SpringApplicationBuilderTests { static class CustomSpringApplication extends SpringApplication { - private final ResourceLoader resourceLoader; + private final @Nullable ResourceLoader resourceLoader; - CustomSpringApplication(ResourceLoader resourceLoader, Class... primarySources) { + CustomSpringApplication(@Nullable ResourceLoader resourceLoader, Class... primarySources) { super(resourceLoader, primarySources); this.resourceLoader = resourceLoader; } @@ -364,10 +382,10 @@ class SpringApplicationBuilderTests { private final ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext()); - private ResourceLoader resourceLoader; + private @Nullable ResourceLoader resourceLoader; @Override - public void setParent(ApplicationContext parent) { + public void setParent(@Nullable ApplicationContext parent) { this.applicationContext.setParent(parent); } @@ -381,7 +399,7 @@ class SpringApplicationBuilderTests { this.resourceLoader = resourceLoader; } - ResourceLoader getResourceLoader() { + @Nullable ResourceLoader getResourceLoader() { return this.resourceLoader; } @@ -392,7 +410,7 @@ class SpringApplicationBuilderTests { } @Override - public ApplicationContext getParent() { + public @Nullable ApplicationContext getParent() { return this.applicationContext.getParent(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java b/core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java index f794be42a12..4b53df2b28b 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java @@ -58,6 +58,7 @@ class CloudPlatformTests { void getActiveWhenHasVcapApplicationShouldReturnCloudFoundry() { Environment environment = new MockEnvironment().withProperty("VCAP_APPLICATION", "---"); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.CLOUD_FOUNDRY); assertThat(platform.isActive(environment)).isTrue(); } @@ -66,6 +67,7 @@ class CloudPlatformTests { void getActiveWhenHasVcapServicesShouldReturnCloudFoundry() { Environment environment = new MockEnvironment().withProperty("VCAP_SERVICES", "---"); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.CLOUD_FOUNDRY); assertThat(platform.isActive(environment)).isTrue(); } @@ -74,6 +76,7 @@ class CloudPlatformTests { void getActiveWhenHasDynoShouldReturnHeroku() { Environment environment = new MockEnvironment().withProperty("DYNO", "---"); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.HEROKU); assertThat(platform.isActive(environment)).isTrue(); } @@ -82,6 +85,7 @@ class CloudPlatformTests { void getActiveWhenHasHcLandscapeShouldReturnSap() { Environment environment = new MockEnvironment().withProperty("HC_LANDSCAPE", "---"); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.SAP); assertThat(platform.isActive(environment)).isTrue(); } @@ -90,6 +94,7 @@ class CloudPlatformTests { void getActiveWhenHasNomadAllocIdShouldReturnNomad() { Environment environment = new MockEnvironment().withProperty("NOMAD_ALLOC_ID", "---"); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.NOMAD); assertThat(platform.isActive(environment)).isTrue(); } @@ -101,6 +106,7 @@ class CloudPlatformTests { envVars.put("KUBERNETES_SERVICE_PORT", "8080"); Environment environment = getEnvironmentWithEnvVariables(envVars); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.KUBERNETES); assertThat(platform.isActive(environment)).isTrue(); } @@ -128,6 +134,7 @@ class CloudPlatformTests { envVars.put("EXAMPLE_SERVICE_PORT", "8080"); Environment environment = getEnvironmentWithEnvVariables(envVars); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.KUBERNETES); assertThat(platform.isActive(environment)).isTrue(); } @@ -149,6 +156,7 @@ class CloudPlatformTests { envVars.put("WEBSITE_SKU", "1234"); Environment environment = getEnvironmentWithEnvVariables(envVars); CloudPlatform platform = CloudPlatform.getActive(environment); + assertThat(platform).isNotNull(); assertThat(platform).isEqualTo(CloudPlatform.AZURE_APP_SERVICE); assertThat(platform.isActive(environment)).isTrue(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/ApplicationPidFileWriterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/ApplicationPidFileWriterTests.java index e55b5ed7006..0f740b6f778 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/ApplicationPidFileWriterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/ApplicationPidFileWriterTests.java @@ -57,6 +57,7 @@ class ApplicationPidFileWriterTests { new String[] {}, mock(ConfigurableApplicationContext.class)); @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @BeforeEach diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java index 38230a33569..3464d8cbb38 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -87,7 +88,8 @@ class ContextIdApplicationContextInitializerTests { assertThat(createContext(parent).getId()).isEqualTo("application"); } - private ConfigurableApplicationContext createContext(ConfigurableApplicationContext parent, String... properties) { + private ConfigurableApplicationContext createContext(@Nullable ConfigurableApplicationContext parent, + String... properties) { ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, properties); if (parent != null) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java index 183b379bc44..20f9bfec478 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.context; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -39,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ class TypeExcludeFilterTests { - private AnnotationConfigApplicationContext context; + private @Nullable AnnotationConfigApplicationContext context; @AfterEach void cleanUp() { @@ -56,8 +57,10 @@ class TypeExcludeFilterTests { this.context.register(Config.class); this.context.refresh(); assertThat(this.context.getBean(ExampleComponent.class)).isNotNull(); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(ExampleFilteredComponent.class)); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(ExampleFilteredComponent.class); + }); } @Configuration(proxyBeanMethods = false) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ConfigurationsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ConfigurationsTests.java index 6985c2a31cb..26addd3e984 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ConfigurationsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ConfigurationsTests.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.function.Function; import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.core.Ordered; @@ -44,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ConfigurationsTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenClassesIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new TestConfigurations((Collection>) null)) .withMessageContaining("'classes' must not be null"); @@ -91,7 +93,7 @@ class ConfigurationsTests { } TestConfigurations(UnaryOperator>> sorter, Collection> classes, - Function, String> beanNameGenerator) { + @Nullable Function, String> beanNameGenerator) { super(sorter, classes, beanNameGenerator); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java index 4dbcedadfc1..92f3d0cd3ae 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.origin.Origin; @@ -120,7 +121,9 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests { private Consumer propertyNameAndOriginOf(String propertyName, String origin) { return (ex) -> { assertThat(ex.getPropertyName()).isEqualTo(propertyName); - assertThat(((PropertySourceOrigin) (ex.getOrigin())).getPropertySource().getName()).isEqualTo(origin); + PropertySourceOrigin actualOrigin = (PropertySourceOrigin) (ex.getOrigin()); + assertThat(actualOrigin).isNotNull(); + assertThat(actualOrigin.getPropertySource().getName()).isEqualTo(origin); }; } @@ -135,7 +138,7 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests { } @Override - public Origin getOrigin(String key) { + public @Nullable Origin getOrigin(String key) { if (getSource().containsKey(key)) { return new PropertySourceOrigin(this, key); } @@ -155,7 +158,7 @@ class ConfigDataEnvironmentContributorPlaceholdersResolverTests { } @Override - boolean isActive(ConfigDataActivationContext activationContext) { + boolean isActive(@Nullable ConfigDataActivationContext activationContext) { return this.active; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java index 998f7f28598..eaa2a601ce7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.cloud.CloudPlatform; @@ -30,7 +31,9 @@ import org.springframework.boot.context.config.ConfigData.Option; import org.springframework.boot.context.config.ConfigData.PropertySourceOptions; import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.ImportPhase; import org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind; +import org.springframework.boot.context.properties.source.ConfigurationProperty; import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.mock.env.MockPropertySource; @@ -110,9 +113,11 @@ class ConfigDataEnvironmentContributorTests { ConfigData configData = new ConfigData(Collections.singleton(propertySource)); ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null, false, configData, 0, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE); - assertThat(contributor.getConfigurationPropertySource() - .getConfigurationProperty(ConfigurationPropertyName.of("spring")) - .getValue()).isEqualTo("boot"); + ConfigurationPropertySource source = contributor.getConfigurationPropertySource(); + assertThat(source).isNotNull(); + ConfigurationProperty spring = source.getConfigurationProperty(ConfigurationPropertyName.of("spring")); + assertThat(spring).isNotNull(); + assertThat(spring.getValue()).isEqualTo("boot"); } @Test @@ -379,8 +384,8 @@ class ConfigDataEnvironmentContributorTests { new ConfigData(Collections.singleton(new MockPropertySource())), 0); } - private ConfigDataEnvironmentContributor createBoundContributor(ConfigDataResource resource, ConfigData configData, - int propertySourceIndex) { + private ConfigDataEnvironmentContributor createBoundContributor(@Nullable ConfigDataResource resource, + ConfigData configData, int propertySourceIndex) { ConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION, resource, false, configData, propertySourceIndex, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE); @@ -394,7 +399,9 @@ class ConfigDataEnvironmentContributorTests { } private String getLocationName(ConfigDataEnvironmentContributor contributor) { - return contributor.getResource().toString(); + ConfigDataResource resource = contributor.getResource(); + assertThat(resource).isNotNull(); + return resource.toString(); } static class TestResource extends ConfigDataResource { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java index e26351de420..17201575fdd 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java @@ -63,6 +63,7 @@ class ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegra private SpringApplication application; @TempDir + @SuppressWarnings("NullAway.Init") public File temp; @BeforeEach diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java index 586f09080a1..ed7460ceff3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java @@ -32,6 +32,7 @@ import java.util.Properties; import java.util.UUID; import org.assertj.core.api.Condition; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -84,6 +85,7 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { private SpringApplication application; @TempDir + @SuppressWarnings("NullAway.Init") public File temp; @BeforeEach @@ -814,7 +816,7 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { MapPropertySource propertySource = new MapPropertySource("defaultProperties", source) { @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { if ("spring.config.name".equals(name)) { return "gh17001"; } @@ -1088,8 +1090,11 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { binder.bind("my.value", Bindable.of(String.class), bindHandler); assertThat(properties).hasSize(1); Origin origin = properties.get(0).getOrigin(); + assertThat(origin).isNotNull(); assertThat(origin.toString()).contains("imported.properties"); - assertThat(origin.getParent().toString()).contains("application.properties"); + Origin parent = origin.getParent(); + assertThat(parent).isNotNull(); + assertThat(parent.toString()).contains("application.properties"); } @Test @@ -1315,7 +1320,7 @@ class ConfigDataEnvironmentPostProcessorIntegrationTests { static class Loader implements ConfigDataLoader { @Override - public ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource) + public @Nullable ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource) throws IOException, ConfigDataResourceNotFoundException { if (resource.isOptional()) { return null; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java index 257726f15b6..47b14365409 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.config; import java.util.Collections; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; @@ -51,13 +52,15 @@ class ConfigDataEnvironmentPostProcessorTests { private final SpringApplication application = new SpringApplication(); - private ConfigDataEnvironment configDataEnvironment; + private @Nullable ConfigDataEnvironment configDataEnvironment; - private ConfigDataEnvironmentPostProcessor postProcessor; + private @Nullable ConfigDataEnvironmentPostProcessor postProcessor; @Test void postProcessEnvironmentWhenNoLoaderCreatesDefaultLoaderInstance() { setupMocksAndSpies(); + assertThat(this.configDataEnvironment).isNotNull(); + assertThat(this.postProcessor).isNotNull(); willReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any()); this.postProcessor.postProcessEnvironment(this.environment, this.application); then(this.postProcessor).should() @@ -70,6 +73,8 @@ class ConfigDataEnvironmentPostProcessorTests { @Test void postProcessEnvironmentWhenCustomLoaderUsesSpecifiedLoaderInstance() { setupMocksAndSpies(); + assertThat(this.configDataEnvironment).isNotNull(); + assertThat(this.postProcessor).isNotNull(); ResourceLoader resourceLoader = mock(ResourceLoader.class); this.application.setResourceLoader(resourceLoader); willReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any()); @@ -83,6 +88,8 @@ class ConfigDataEnvironmentPostProcessorTests { @Test void postProcessEnvironmentWhenHasAdditionalProfilesOnSpringApplicationUsesAdditionalProfiles() { setupMocksAndSpies(); + assertThat(this.configDataEnvironment).isNotNull(); + assertThat(this.postProcessor).isNotNull(); this.application.setAdditionalProfiles("dev"); willReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any()); this.postProcessor.postProcessEnvironment(this.environment, this.application); @@ -95,6 +102,8 @@ class ConfigDataEnvironmentPostProcessorTests { @Test void postProcessEnvironmentWhenNoActiveProfiles() { setupMocksAndSpies(); + assertThat(this.configDataEnvironment).isNotNull(); + assertThat(this.postProcessor).isNotNull(); willReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any()); this.postProcessor.postProcessEnvironment(this.environment, this.application); then(this.postProcessor).should().getConfigDataEnvironment(any(), any(ResourceLoader.class), any()); @@ -113,7 +122,9 @@ class ConfigDataEnvironmentPostProcessorTests { assertThat(this.environment.getPropertySources()).hasSizeGreaterThan(before); assertThat(this.environment.getActiveProfiles()).containsExactly("dev"); assertThat(listener.getAddedPropertySources()).isNotEmpty(); - assertThat(listener.getProfiles().getActive()).containsExactly("dev"); + Profiles profiles = listener.getProfiles(); + assertThat(profiles).isNotNull(); + assertThat(profiles.getActive()).containsExactly("dev"); assertThat(listener.getAddedPropertySources().stream().anyMatch((added) -> hasDevProfile(added.getResource()))) .isTrue(); } @@ -147,7 +158,7 @@ class ConfigDataEnvironmentPostProcessorTests { this.postProcessor = spy(new ConfigDataEnvironmentPostProcessor(Supplier::get, new DefaultBootstrapContext())); } - private boolean hasDevProfile(ConfigDataResource resource) { + private boolean hasDevProfile(@Nullable ConfigDataResource resource) { return (resource instanceof StandardConfigDataResource standardResource) && "dev".equals(standardResource.getProfile()); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java index af5a3df8085..47bca02441d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.function.Supplier; import org.assertj.core.api.InstanceOfAssertFactories; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.params.ParameterizedTest; @@ -81,8 +82,9 @@ class ConfigDataEnvironmentTests { this.environment.setProperty("spring", "boot"); TestConfigDataEnvironment configDataEnvironment = new TestConfigDataEnvironment(this.logFactory, this.bootstrapContext, this.environment, this.resourceLoader, this.additionalProfiles, null); - assertThat(configDataEnvironment.getConfigDataLocationResolversBinder().bind("spring", String.class).get()) - .isEqualTo("boot"); + Binder binder = configDataEnvironment.getConfigDataLocationResolversBinder(); + assertThat(binder).isNotNull(); + assertThat(binder.bind("spring", String.class).get()).isEqualTo("boot"); } @Test @@ -335,8 +337,9 @@ class ConfigDataEnvironmentTests { AddedPropertySource addedPropertySource = listener.getAddedPropertySources().get(0); assertThat(addedPropertySource.getPropertySource().getProperty("spring")).isEqualTo("boot"); assertThat(addedPropertySource.getLocation()).hasToString("classpath:custom/config.properties"); - assertThat(addedPropertySource.getResource().toString()).contains("class path resource") - .contains("custom/config.properties"); + ConfigDataResource resource = addedPropertySource.getResource(); + assertThat(resource).isNotNull(); + assertThat(resource.toString()).contains("class path resource").contains("custom/config.properties"); } @Test @@ -346,7 +349,9 @@ class ConfigDataEnvironmentTests { ConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext, this.environment, this.resourceLoader, this.additionalProfiles, listener); configDataEnvironment.processAndApply(); - assertThat(listener.getProfiles().getActive()).containsExactly("one", "two", "three"); + Profiles profiles = listener.getProfiles(); + assertThat(profiles).isNotNull(); + assertThat(profiles.getActive()).containsExactly("one", "two", "three"); } @Test @@ -384,11 +389,12 @@ class ConfigDataEnvironmentTests { static class TestConfigDataEnvironment extends ConfigDataEnvironment { - private Binder configDataLocationResolversBinder; + private @Nullable Binder configDataLocationResolversBinder; TestConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment, ResourceLoader resourceLoader, - Collection additionalProfiles, ConfigDataEnvironmentUpdateListener environmentUpdateListener) { + Collection additionalProfiles, + @Nullable ConfigDataEnvironmentUpdateListener environmentUpdateListener) { super(logFactory, bootstrapContext, environment, resourceLoader, additionalProfiles, environmentUpdateListener); } @@ -400,7 +406,7 @@ class ConfigDataEnvironmentTests { return super.createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader); } - Binder getConfigDataLocationResolversBinder() { + @Nullable Binder getConfigDataLocationResolversBinder() { return this.configDataLocationResolversBinder; } @@ -409,7 +415,7 @@ class ConfigDataEnvironmentTests { static class SeparateClassLoaderConfigDataLoader implements ConfigDataLoader { @Override - public ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) + public @Nullable ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException, ConfigDataResourceNotFoundException { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java index 97f4b487ac2..49ff2cbc61e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java @@ -47,24 +47,31 @@ class ConfigDataImporterTests { private final DeferredLogFactory logFactory = Supplier::get; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataLocationResolvers resolvers; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataLoaders loaders; @Mock + @SuppressWarnings("NullAway.Init") private Binder binder; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataLocationResolverContext locationResolverContext; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataLoaderContext loaderContext; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataActivationContext activationContext; @Mock + @SuppressWarnings("NullAway.Init") private Profiles profiles; @BeforeEach diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoaderTests.java index 95178f9a53a..618360ff283 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoaderTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.config; import java.io.IOException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -43,7 +44,8 @@ class ConfigDataLoaderTests { static class TestConfigDataLoader implements ConfigDataLoader { @Override - public ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource) throws IOException { + public @Nullable ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource) + throws IOException { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoadersTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoadersTests.java index 0fb289461f3..8045d9e4e7c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoadersTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoadersTests.java @@ -16,7 +16,6 @@ package org.springframework.boot.context.config; -import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -25,7 +24,6 @@ import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; import org.springframework.boot.bootstrap.BootstrapContext; import org.springframework.boot.bootstrap.BootstrapRegistry; @@ -56,9 +54,6 @@ class ConfigDataLoadersTests { private final ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class); - @TempDir - private File tempDir; - @Test void createWhenLoaderHasDeferredLogFactoryParameterInjectsDeferredLogFactory() { MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader(); @@ -103,6 +98,7 @@ class ConfigDataLoadersTests { springFactoriesLoader); TestConfigDataResource location = new TestConfigDataResource("test"); ConfigData loaded = loaders.load(this.context, location); + assertThat(loaded).isNotNull(); assertThat(getLoader(loaded)).isInstanceOf(TestConfigDataLoader.class); } @@ -136,11 +132,14 @@ class ConfigDataLoadersTests { springFactoriesLoader); TestConfigDataResource location = new TestConfigDataResource("test"); ConfigData loaded = loaders.load(this.context, location); + assertThat(loaded).isNotNull(); assertThat(getLoader(loaded)).isInstanceOf(SpecificConfigDataLoader.class); } private ConfigDataLoader getLoader(ConfigData loaded) { - return (ConfigDataLoader) loaded.getPropertySources().get(0).getProperty("loader"); + ConfigDataLoader result = (ConfigDataLoader) loaded.getPropertySources().get(0).getProperty("loader"); + assertThat(result).isNotNull(); + return result; } private static ConfigData createConfigData(ConfigDataLoader loader, ConfigDataResource resource) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionTests.java index 8870f0b3c70..9eeb9f228c6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionTests.java @@ -39,6 +39,7 @@ class ConfigDataLocationNotFoundExceptionTests { this.location); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenLocationIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigDataLocationNotFoundException(null)) .withMessage("'location' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolverTests.java index 3da4592a06c..bb370e0f52f 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolverTests.java @@ -16,10 +16,14 @@ package org.springframework.boot.context.config; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.mock.env.MockEnvironment; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -37,7 +41,10 @@ class ConfigDataLocationResolverTests { @Test void resolveProfileSpecificReturnsEmptyList() { - assertThat(this.resolver.resolveProfileSpecific(this.context, null, null)).isEmpty(); + ConfigDataLocation location = ConfigDataLocation.of("location"); + MockEnvironment environment = new MockEnvironment(); + Profiles profiles = new Profiles(environment, Binder.get(environment), null); + assertThat(this.resolver.resolveProfileSpecific(this.context, location, profiles)).isEmpty(); } static class TestConfigDataLocationResolver implements ConfigDataLocationResolver { @@ -50,7 +57,7 @@ class ConfigDataLocationResolverTests { @Override public List resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) { - return null; + return Collections.emptyList(); } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java index bd70e554ef0..47aab9e4eea 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java @@ -56,15 +56,19 @@ class ConfigDataLocationResolversTests { private final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); @Mock + @SuppressWarnings("NullAway.Init") private Binder binder; @Mock + @SuppressWarnings("NullAway.Init") private ConfigDataLocationResolverContext context; @Mock + @SuppressWarnings("NullAway.Init") private Profiles profiles; @TempDir + @SuppressWarnings("NullAway.Init") private File tempDir; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java index 4fe636ef42d..388d811854d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.UUID; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.ResourcePatternHint; @@ -60,7 +61,7 @@ class ConfigDataLocationRuntimeHintsTests { RuntimeHints hints = new RuntimeHints(); new TestConfigDataLocationRuntimeHints() { @Override - protected List getFileNames(ClassLoader classLoader) { + protected List getFileNames(@Nullable ClassLoader classLoader) { return List.of("test"); } @@ -77,7 +78,7 @@ class ConfigDataLocationRuntimeHintsTests { RuntimeHints hints = new RuntimeHints(); new TestConfigDataLocationRuntimeHints() { @Override - protected List getLocations(ClassLoader classLoader) { + protected List getLocations(@Nullable ClassLoader classLoader) { return List.of("config/"); } }.registerHints(hints, Thread.currentThread().getContextClassLoader()); @@ -93,7 +94,7 @@ class ConfigDataLocationRuntimeHintsTests { RuntimeHints hints = new RuntimeHints(); new ConfigDataLocationRuntimeHints() { @Override - protected List getExtensions(ClassLoader classLoader) { + protected List getExtensions(@Nullable ClassLoader classLoader) { return List.of(".conf"); } }.registerHints(hints, Thread.currentThread().getContextClassLoader()); @@ -106,7 +107,7 @@ class ConfigDataLocationRuntimeHintsTests { RuntimeHints hints = new RuntimeHints(); new ConfigDataLocationRuntimeHints() { @Override - protected List getLocations(ClassLoader classLoader) { + protected List getLocations(@Nullable ClassLoader classLoader) { return List.of(UUID.randomUUID().toString()); } }.registerHints(hints, Thread.currentThread().getContextClassLoader()); @@ -138,7 +139,7 @@ class ConfigDataLocationRuntimeHintsTests { } @Override - protected SpringFactoriesLoader getSpringFactoriesLoader(ClassLoader classLoader) { + protected SpringFactoriesLoader getSpringFactoriesLoader(@Nullable ClassLoader classLoader) { return this.springFactoriesLoader; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java index 80e7a2647c2..9085e581ab4 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java @@ -38,6 +38,7 @@ class ConfigDataNotFoundFailureAnalyzerTests { ConfigDataLocation location = ConfigDataLocation.of("test"); ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result).isNotNull(); assertThat(result.getDescription()).isEqualTo("Config data location 'test' does not exist"); assertThat(result.getAction()) .isEqualTo("Check that the value 'test' is correct, or prefix it with 'optional:'"); @@ -48,6 +49,7 @@ class ConfigDataNotFoundFailureAnalyzerTests { ConfigDataLocation location = ConfigDataLocation.of("optional:test"); ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result).isNotNull(); assertThat(result.getDescription()).isEqualTo("Config data location 'optional:test' does not exist"); assertThat(result.getAction()).isEqualTo("Check that the value 'optional:test' is correct"); } @@ -57,6 +59,7 @@ class ConfigDataNotFoundFailureAnalyzerTests { ConfigDataLocation location = ConfigDataLocation.of("test").withOrigin(new TestOrigin("origin")); ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location); FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result).isNotNull(); assertThat(result.getDescription()).isEqualTo("Config data location 'test' does not exist"); assertThat(result.getAction()) .isEqualTo("Check that the value 'test' at origin is correct, or prefix it with 'optional:'"); @@ -67,6 +70,7 @@ class ConfigDataNotFoundFailureAnalyzerTests { ConfigDataResource resource = new TestConfigDataResource("myresource"); ConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource); FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result).isNotNull(); assertThat(result.getDescription()).isEqualTo("Config data resource 'myresource' does not exist"); assertThat(result.getAction()).isEqualTo("Check that the value is correct"); } @@ -78,6 +82,7 @@ class ConfigDataNotFoundFailureAnalyzerTests { ConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource) .withLocation(location); FailureAnalysis result = this.analyzer.analyze(exception); + assertThat(result).isNotNull(); assertThat(result.getDescription()) .isEqualTo("Config data resource 'myresource' via location 'test' does not exist"); assertThat(result.getAction()) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesTests.java index a1ae0a75c71..6f080b052d6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesTests.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.cloud.CloudPlatform; @@ -39,9 +40,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ class ConfigDataPropertiesTests { - private static final CloudPlatform NULL_CLOUD_PLATFORM = null; + private static final @Nullable CloudPlatform NULL_CLOUD_PLATFORM = null; - private static final Profiles NULL_PROFILES = null; + private static final @Nullable Profiles NULL_PROFILES = null; private static final List NO_IMPORTS = Collections.emptyList(); @@ -173,6 +174,7 @@ class ConfigDataPropertiesTests { ConfigDataProperties properties = ConfigDataProperties.get(binder); ConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, createTestProfiles()); + assertThat(properties).isNotNull(); assertThat(properties.isActive(context)).isTrue(); } @@ -185,6 +187,7 @@ class ConfigDataPropertiesTests { ConfigDataProperties properties = ConfigDataProperties.get(binder); ConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, createTestProfiles()); + assertThat(properties).isNotNull(); assertThat(properties.isActive(context)).isFalse(); } @@ -197,6 +200,7 @@ class ConfigDataPropertiesTests { ConfigDataProperties properties = ConfigDataProperties.get(binder); ConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, createTestProfiles()); + assertThat(properties).isNotNull(); assertThat(properties.isActive(context)).isFalse(); } @@ -208,6 +212,7 @@ class ConfigDataPropertiesTests { ConfigDataProperties properties = ConfigDataProperties.get(binder); ConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, createTestProfiles()); + assertThat(properties).isNotNull(); assertThat(properties.isActive(context)).isTrue(); } @@ -217,6 +222,7 @@ class ConfigDataPropertiesTests { source.put("spring.config.import", "one,two,three"); Binder binder = new Binder(source); ConfigDataProperties properties = ConfigDataProperties.get(binder); + assertThat(properties).isNotNull(); assertThat(properties.getImports().get(1).getOrigin()) .hasToString("\"spring.config.import\" from property source \"source\""); } @@ -229,6 +235,7 @@ class ConfigDataPropertiesTests { source.put("spring.config.import[2]", "three"); Binder binder = new Binder(source); ConfigDataProperties properties = ConfigDataProperties.get(binder); + assertThat(properties).isNotNull(); assertThat(properties.getImports().get(1).getOrigin()) .hasToString("\"spring.config.import[1]\" from property source \"source\""); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundExceptionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundExceptionTests.java index a06b27cb080..0c5d8892540 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundExceptionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundExceptionTests.java @@ -49,6 +49,7 @@ class ConfigDataResourceNotFoundExceptionTests { private File missing; @TempDir + @SuppressWarnings("NullAway.Init") File temp; @BeforeEach @@ -61,6 +62,7 @@ class ConfigDataResourceNotFoundExceptionTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenResourceIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigDataResourceNotFoundException(null)) .withMessage("'resource' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataTests.java index 20204d74af1..aa7a8aac2d6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataTests.java @@ -42,12 +42,14 @@ import static org.mockito.Mockito.mock; class ConfigDataTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertySourcesIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigData(null)) .withMessage("'propertySources' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenOptionsIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigData(Collections.emptyList(), (Option[]) null)) .withMessage("'options' must not be null"); @@ -127,8 +129,9 @@ class ConfigDataTests { @Test void propertySourceOptionsAlwaysReturnsSameOptionsEachTime() { PropertySourceOptions options = PropertySourceOptions.always(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES); - assertThat(options.get(mock(PropertySource.class)).asSet()).containsExactly(Option.IGNORE_IMPORTS, - Option.IGNORE_PROFILES); + Options propertySourceOptions = options.get(mock(PropertySource.class)); + assertThat(propertySourceOptions).isNotNull(); + assertThat(propertySourceOptions.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES); } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoaderTests.java index 476219bed4b..197e38e762c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoaderTests.java @@ -44,6 +44,7 @@ class ConfigTreeConfigDataLoaderTests { private final ConfigDataLoaderContext loaderContext = mock(ConfigDataLoaderContext.class); @TempDir + @SuppressWarnings("NullAway.Init") Path directory; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolverTests.java index 5d7e0e379c0..0dd2fc040fe 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolverTests.java @@ -42,6 +42,7 @@ class ConfigTreeConfigDataLocationResolverTests { private final ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class); @TempDir + @SuppressWarnings("NullAway.Init") File temp; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataResourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataResourceTests.java index 0cd8a899e5c..f5f8ef71a11 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataResourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataResourceTests.java @@ -33,12 +33,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ConfigTreeConfigDataResourceTests { @Test + @SuppressWarnings("NullAway") // Test null check void constructorWhenPathStringIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreeConfigDataResource((String) null)) .withMessage("'path' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void constructorWhenPathIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreeConfigDataResource((Path) null)) .withMessage("'path' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/LocationResourceLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/LocationResourceLoaderTests.java index 1d4e3e91438..3d44ff259e3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/LocationResourceLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/LocationResourceLoaderTests.java @@ -40,6 +40,7 @@ class LocationResourceLoaderTests { private final LocationResourceLoader loader = new LocationResourceLoader(new DefaultResourceLoader()); @TempDir + @SuppressWarnings("NullAway.Init") File temp; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java index a956ea0f059..022539d3394 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java @@ -258,7 +258,7 @@ class StandardConfigDataLocationResolverTests { assertThat(locations).hasSize(1); StandardConfigDataResource resolved = locations.get(0); assertThat(resolved.getResource().getFilename()).endsWith("application-props-no-extension"); - ConfigData loaded = new StandardConfigDataLoader().load(null, resolved); + ConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved); PropertySource propertySource = loaded.getPropertySources().get(0); assertThat(propertySource.getProperty("withnoextension")).isEqualTo("test"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataResourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataResourceTests.java index a576e1248ed..7dca9f9f6d3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataResourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataResourceTests.java @@ -46,12 +46,14 @@ class StandardConfigDataResourceTests { private final Resource resource = mock(Resource.class); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenReferenceIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new StandardConfigDataResource(null, this.resource)) .withMessage("'reference' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenResourceIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new StandardConfigDataResource(this.reference, null)) .withMessage("'resource' must not be null"); @@ -78,6 +80,7 @@ class StandardConfigDataResourceTests { @WithResource(name = "test.resource", content = "test") void equalsAndHashCodeWhenSameUnderlyingResource(@ResourcePath("test.resource") Path path) throws IOException { Path directory = path.getParent(); + assertThat(directory).isNotNull(); URLClassLoader classLoader = new URLClassLoader(new URL[] { directory.toUri().toURL() }, getClass().getClassLoader()); ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java index eecdc22242c..1cdded4dca3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java @@ -21,12 +21,16 @@ import java.util.Collections; import java.util.List; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.bootstrap.BootstrapContextClosedEvent; import org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.ApplicationListener; import org.springframework.core.env.MapPropertySource; +import static org.assertj.core.api.Assertions.assertThat; + /** * Test classes used with * {@link ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests} to show how @@ -50,6 +54,7 @@ class TestConfigDataBootstrap { context.getBootstrapContext() .registerIfAbsent(ResolverHelper.class, InstanceSupplier.from(() -> new ResolverHelper(location))); ResolverHelper helper = context.getBootstrapContext().get(ResolverHelper.class); + assertThat(helper).isNotNull(); return Collections.singletonList(new Resource(helper)); } @@ -63,6 +68,7 @@ class TestConfigDataBootstrap { .registerIfAbsent(LoaderHelper.class, (bootstrapContext) -> new LoaderHelper(location, () -> bootstrapContext.get(Binder.class))); LoaderHelper helper = context.getBootstrapContext().get(LoaderHelper.class); + assertThat(helper).isNotNull(); context.getBootstrapContext().addCloseListener(helper); return new ConfigData( Collections.singleton(new MapPropertySource("loaded", Collections.singletonMap("test", "test")))); @@ -118,11 +124,11 @@ class TestConfigDataBootstrap { return this.location; } - String getBound() { + @Nullable String getBound() { return this.binder.get().bind("myprop", String.class).orElse(null); } - String getProfileBound() { + @Nullable String getProfileBound() { return this.binder.get().bind("myprofileprop", String.class).orElse(null); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataEnvironmentUpdateListener.java b/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataEnvironmentUpdateListener.java index f0cc0ee5e04..c7a922a0a58 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataEnvironmentUpdateListener.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataEnvironmentUpdateListener.java @@ -20,17 +20,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.env.PropertySource; class TestConfigDataEnvironmentUpdateListener implements ConfigDataEnvironmentUpdateListener { private final List addedPropertySources = new ArrayList<>(); - private Profiles profiles; + private @Nullable Profiles profiles; @Override - public void onPropertySourceAdded(PropertySource propertySource, ConfigDataLocation location, - ConfigDataResource resource) { + public void onPropertySourceAdded(PropertySource propertySource, @Nullable ConfigDataLocation location, + @Nullable ConfigDataResource resource) { this.addedPropertySources.add(new AddedPropertySource(propertySource, location, resource)); } @@ -43,7 +45,7 @@ class TestConfigDataEnvironmentUpdateListener implements ConfigDataEnvironmentUp return Collections.unmodifiableList(this.addedPropertySources); } - Profiles getProfiles() { + @Nullable Profiles getProfiles() { return this.profiles; } @@ -51,12 +53,12 @@ class TestConfigDataEnvironmentUpdateListener implements ConfigDataEnvironmentUp private final PropertySource propertySource; - private final ConfigDataLocation location; + private final @Nullable ConfigDataLocation location; - private final ConfigDataResource resource; + private final @Nullable ConfigDataResource resource; - AddedPropertySource(PropertySource propertySource, ConfigDataLocation location, - ConfigDataResource resource) { + AddedPropertySource(PropertySource propertySource, @Nullable ConfigDataLocation location, + @Nullable ConfigDataResource resource) { this.propertySource = propertySource; this.location = location; this.resource = resource; @@ -66,11 +68,11 @@ class TestConfigDataEnvironmentUpdateListener implements ConfigDataEnvironmentUp return this.propertySource; } - ConfigDataLocation getLocation() { + @Nullable ConfigDataLocation getLocation() { return this.location; } - ConfigDataResource getResource() { + @Nullable ConfigDataResource getResource() { return this.resource; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/event/EventPublishingRunListenerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/event/EventPublishingRunListenerTests.java index 442f313ed91..ff389d803ba 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/event/EventPublishingRunListenerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/event/EventPublishingRunListenerTests.java @@ -32,6 +32,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.StandardEnvironment; +import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -45,6 +46,8 @@ import static org.mockito.Mockito.mock; */ class EventPublishingRunListenerTests { + private static final String[] NO_ARGS = new String[0]; + @Test void shouldPublishLifecycleEvents() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); @@ -52,11 +55,11 @@ class EventPublishingRunListenerTests { TestApplicationListener applicationListener = new TestApplicationListener(); SpringApplication application = mock(SpringApplication.class); given(application.getListeners()).willReturn(Collections.singleton(applicationListener)); - EventPublishingRunListener publishingListener = new EventPublishingRunListener(application, null); + EventPublishingRunListener publishingListener = new EventPublishingRunListener(application, NO_ARGS); applicationListener.assertReceivedNoEvents(); publishingListener.starting(bootstrapContext); applicationListener.assertReceivedEvent(ApplicationStartingEvent.class); - publishingListener.environmentPrepared(bootstrapContext, null); + publishingListener.environmentPrepared(bootstrapContext, new MockEnvironment()); applicationListener.assertReceivedEvent(ApplicationEnvironmentPreparedEvent.class); publishingListener.contextPrepared(context); applicationListener.assertReceivedEvent(ApplicationContextInitializedEvent.class); @@ -78,7 +81,7 @@ class EventPublishingRunListenerTests { ApplicationListener listener = (event) -> event.getSpringApplication() .addListeners(lateAddedApplicationListener); application.addListeners(listener); - EventPublishingRunListener runListener = new EventPublishingRunListener(application, null); + EventPublishingRunListener runListener = new EventPublishingRunListener(application, NO_ARGS); runListener.starting(bootstrapContext); runListener.environmentPrepared(bootstrapContext, environment); lateAddedApplicationListener.assertReceivedEvent(ApplicationEnvironmentPreparedEvent.class); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerIntegrationTests.java index 890a0d3a6d2..b85c89e5ed2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerIntegrationTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.logging; import java.io.File; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; @@ -103,7 +104,7 @@ class LoggingApplicationListenerIntegrationTests { private final LoggingSystem loggingSystem; - private final LogFile logFile; + private final @Nullable LogFile logFile; SampleService(LoggingSystem loggingSystem, ObjectProvider logFile) { this.loggingSystem = loggingSystem; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java index b88529bc2b0..b213a57f9c1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java @@ -40,6 +40,7 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -59,6 +60,7 @@ import org.springframework.boot.logging.AbstractLoggingSystem; import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggerConfiguration; +import org.springframework.boot.logging.LoggerGroup; import org.springframework.boot.logging.LoggerGroups; import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingSystem; @@ -118,6 +120,7 @@ class LoggingApplicationListenerTests { private final GenericApplicationContext context = new GenericApplicationContext(); @TempDir + @SuppressWarnings("NullAway.Init") public Path tempDir; private File logFile; @@ -149,14 +152,12 @@ class LoggingApplicationListenerTests { System.clearProperty(LoggingSystem.class.getName()); System.clearProperty(LoggingSystem.SYSTEM_PROPERTY); System.getProperties().keySet().retainAll(this.systemPropertyNames); - if (this.context != null) { - this.context.close(); - } + this.context.close(); } @Test void baseConfigLocation() { - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world", new RuntimeException("Expected")); assertThat(this.output).contains("Hello world"); assertThat(this.output).doesNotContain("???"); @@ -168,7 +169,7 @@ class LoggingApplicationListenerTests { @WithNonDefaultXmlResource void overrideConfigLocation() { addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world"); assertThat(this.output).contains("Hello world").doesNotContain("???").startsWith("null ").endsWith("BOOTBOOT"); } @@ -179,7 +180,7 @@ class LoggingApplicationListenerTests { multicastEvent(this.listener, new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS)); assertThatIllegalStateException() - .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader())); + .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader())); assertThat(output).contains("Deliberately broken"); } @@ -187,7 +188,7 @@ class LoggingApplicationListenerTests { @WithNonDefaultXmlResource void trailingWhitespaceInLoggingConfigShouldBeTrimmed() { addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml "); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world"); assertThat(this.output).contains("Hello world").doesNotContain("???").startsWith("null ").endsWith("BOOTBOOT"); } @@ -196,7 +197,7 @@ class LoggingApplicationListenerTests { void overrideConfigDoesNotExist() { addPropertiesToEnvironment(this.context, "logging.config=doesnotexist.xml"); assertThatIllegalStateException() - .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader())); + .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader())); assertThat(this.output) .contains("Logging system failed to initialize using configuration from 'doesnotexist.xml'") .doesNotContain("JoranException"); @@ -206,7 +207,7 @@ class LoggingApplicationListenerTests { void azureDefaultLoggingConfigDoesNotCauseAFailure() { addPropertiesToEnvironment(this.context, "logging.config=-Djava.util.logging.config.file=\"d:\\home\\site\\wwwroot\\bin\\apache-tomcat-7.0.52\\conf\\logging.properties\""); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world"); assertThat(this.output).contains("Hello world").doesNotContain("???"); assertThat(new File(this.tempDir.toFile(), "/spring.log")).doesNotExist(); @@ -215,7 +216,7 @@ class LoggingApplicationListenerTests { @Test void tomcatNopLoggingConfigDoesNotCauseAFailure() { addPropertiesToEnvironment(this.context, "LOGGING_CONFIG=-Dnop"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world"); assertThat(this.output).contains("Hello world").doesNotContain("???"); assertThat(new File(this.tempDir.toFile(), "/spring.log")).doesNotExist(); @@ -225,7 +226,7 @@ class LoggingApplicationListenerTests { void overrideConfigBroken() { addPropertiesToEnvironment(this.context, "logging.config=classpath:logback-broken.xml"); assertThatIllegalStateException().isThrownBy(() -> { - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(this.output).contains( "Logging system failed to initialize using configuration from 'classpath:logback-broken.xml'"); assertThat(this.output).contains("ConsolAppender"); @@ -237,7 +238,7 @@ class LoggingApplicationListenerTests { void addLogFileProperty() { addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml", "logging.file.name=" + this.logFile); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class); String existingOutput = this.output.toString(); logger.info("Hello world"); @@ -249,7 +250,7 @@ class LoggingApplicationListenerTests { void addLogFilePropertyWithDefault() { assertThat(this.logFile).doesNotExist(); addPropertiesToEnvironment(this.context, "logging.file.name=" + this.logFile); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class); logger.info("Hello world"); assertThat(this.logFile).isFile(); @@ -260,7 +261,7 @@ class LoggingApplicationListenerTests { void addLogPathProperty() { addPropertiesToEnvironment(this.context, "logging.config=classpath:nondefault.xml", "logging.file.path=" + this.tempDir); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); Log logger = LogFactory.getLog(LoggingApplicationListenerTests.class); String existingOutput = this.output.toString(); logger.info("Hello world"); @@ -271,7 +272,7 @@ class LoggingApplicationListenerTests { @Test void parseDebugArg() { addPropertiesToEnvironment(this.context, "debug"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -281,19 +282,22 @@ class LoggingApplicationListenerTests { @Test void parseDebugArgExpandGroups() { addPropertiesToEnvironment(this.context, "debug"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.loggerContext.getLogger("org.springframework.boot.actuate.endpoint.web").debug("testdebugwebgroup"); this.loggerContext.getLogger("org.hibernate.SQL").debug("testdebugsqlgroup"); assertThat(this.output).contains("testdebugwebgroup"); assertThat(this.output).contains("testdebugsqlgroup"); LoggerGroups loggerGroups = (LoggerGroups) ReflectionTestUtils.getField(this.listener, "loggerGroups"); - assertThat(loggerGroups.get("web").getConfiguredLevel()).isEqualTo(LogLevel.DEBUG); + assertThat(loggerGroups).isNotNull(); + LoggerGroup loggerGroup = loggerGroups.get("web"); + assertThat(loggerGroup).isNotNull(); + assertThat(loggerGroup.getConfiguredLevel()).isEqualTo(LogLevel.DEBUG); } @Test void parseTraceArg() { addPropertiesToEnvironment(this.context, "trace"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -312,7 +316,7 @@ class LoggingApplicationListenerTests { private void disableDebugTraceArg(String... environment) { addPropertiesToEnvironment(this.context, environment); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).doesNotContain("testatdebug"); @@ -322,7 +326,7 @@ class LoggingApplicationListenerTests { @Test void parseLevels() { addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot=TRACE"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -332,7 +336,7 @@ class LoggingApplicationListenerTests { @Test void parseLevelsCaseInsensitive() { addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot=TrAcE"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -342,7 +346,7 @@ class LoggingApplicationListenerTests { @Test void parseLevelsTrimsWhitespace() { addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot= trace "); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -352,7 +356,7 @@ class LoggingApplicationListenerTests { @Test void parseLevelsWithPlaceholder() { addPropertiesToEnvironment(this.context, "foo=TRACE", "logging.level.org.springframework.boot=${foo}"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.trace("testattrace"); assertThat(this.output).contains("testatdebug"); @@ -364,13 +368,13 @@ class LoggingApplicationListenerTests { this.logger.setLevel(Level.INFO); addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot=GARBAGE"); assertThatExceptionOfType(BindException.class) - .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader())); + .isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader())); } @Test void parseLevelsNone() { addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot=OFF"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.error("testaterror"); assertThat(this.output).doesNotContain("testatdebug").doesNotContain("testaterror"); @@ -379,7 +383,7 @@ class LoggingApplicationListenerTests { @Test void parseLevelsMapsFalseToOff() { addPropertiesToEnvironment(this.context, "logging.level.org.springframework.boot=false"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); this.logger.error("testaterror"); assertThat(this.output).doesNotContain("testatdebug").doesNotContain("testaterror"); @@ -389,7 +393,7 @@ class LoggingApplicationListenerTests { void parseArgsDisabled() { this.listener.setParseArgs(false); addPropertiesToEnvironment(this.context, "debug"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); assertThat(this.output).doesNotContain("testatdebug"); } @@ -400,7 +404,7 @@ class LoggingApplicationListenerTests { this.listener.setParseArgs(false); multicastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[] { "--debug" })); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); assertThat(this.output).doesNotContain("testatdebug"); } @@ -414,7 +418,7 @@ class LoggingApplicationListenerTests { @Test void defaultExceptionConversionWord() { - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world", new RuntimeException("Wrapper", new RuntimeException("Expected"))); assertThat(this.output).contains("Hello world"); assertThat(this.output).doesNotContain("Wrapped by: java.lang.RuntimeException: Wrapper"); @@ -423,7 +427,7 @@ class LoggingApplicationListenerTests { @Test void overrideExceptionConversionWord() { addPropertiesToEnvironment(this.context, "logging.exceptionConversionWord=%rEx"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.info("Hello world", new RuntimeException("Wrapper", new RuntimeException("Expected"))); assertThat(this.output).contains("Hello world"); assertThat(this.output).contains("Wrapped by: java.lang.RuntimeException: Wrapper"); @@ -434,13 +438,16 @@ class LoggingApplicationListenerTests { TestLoggingApplicationListener listener = new TestLoggingApplicationListener(); Object registered = ReflectionTestUtils.getField(listener, TestLoggingApplicationListener.class, "shutdownHookRegistered"); + assertThat(registered).isNotNull(); ((AtomicBoolean) registered).set(false); System.setProperty(LoggingSystem.class.getName(), TestShutdownHandlerLoggingSystem.class.getName()); multicastEvent(listener, new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS)); - listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(listener.shutdownHook).isNotNull(); listener.shutdownHook.run(); - assertThat(TestShutdownHandlerLoggingSystem.shutdownLatch.await(30, TimeUnit.SECONDS)).isTrue(); + CountDownLatch shutdownLatch = TestShutdownHandlerLoggingSystem.shutdownLatch; + assertThat(shutdownLatch).isNotNull(); + assertThat(shutdownLatch.await(30, TimeUnit.SECONDS)).isTrue(); } @Test @@ -448,11 +455,12 @@ class LoggingApplicationListenerTests { TestLoggingApplicationListener listener = new TestLoggingApplicationListener(); Object registered = ReflectionTestUtils.getField(listener, TestLoggingApplicationListener.class, "shutdownHookRegistered"); + assertThat(registered).isNotNull(); ((AtomicBoolean) registered).set(false); System.setProperty(LoggingSystem.class.getName(), TestShutdownHandlerLoggingSystem.class.getName()); addPropertiesToEnvironment(this.context, "logging.register_shutdown_hook=false"); multicastEvent(listener, new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS)); - listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(listener.shutdownHook).isNull(); } @@ -462,6 +470,7 @@ class LoggingApplicationListenerTests { multicastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener, "loggingSystem"); + assertThat(loggingSystem).isNotNull(); assertThat(loggingSystem.cleanedUp).isFalse(); multicastEvent(new ContextClosedEvent(this.context)); assertThat(loggingSystem.cleanedUp).isTrue(); @@ -473,6 +482,7 @@ class LoggingApplicationListenerTests { multicastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener, "loggingSystem"); + assertThat(loggingSystem).isNotNull(); assertThat(loggingSystem.cleanedUp).isFalse(); GenericApplicationContext childContext = new GenericApplicationContext(); childContext.setParent(this.context); @@ -489,7 +499,7 @@ class LoggingApplicationListenerTests { "logging.file.name=" + this.logFile, "logging.file.path=path", "logging.pattern.console=console", "logging.pattern.file=file", "logging.pattern.level=level", "logging.pattern.correlation=correlation", "logging.pattern.rolling-file-name=my.log.%d{yyyyMMdd}.%i.gz"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).isEqualTo("console"); assertThat(getSystemProperty(LoggingSystemProperty.FILE_PATTERN)).isEqualTo("file"); assertThat(getSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD)).isEqualTo("conversion"); @@ -503,14 +513,14 @@ class LoggingApplicationListenerTests { void environmentPropertiesIgnoreUnresolvablePlaceholders() { // gh-7719 addPropertiesToEnvironment(this.context, "logging.pattern.console=console ${doesnotexist}"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).isEqualTo("console ${doesnotexist}"); } @Test void environmentPropertiesResolvePlaceholders() { addPropertiesToEnvironment(this.context, "logging.pattern.console=console ${pid}"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)) .isEqualTo(this.context.getEnvironment().getProperty("logging.pattern.console")); } @@ -518,7 +528,7 @@ class LoggingApplicationListenerTests { @Test void logFilePropertiesCanReferenceSystemProperties() { addPropertiesToEnvironment(this.context, "logging.file.name=" + this.tempDir + "${PID}.log"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertThat(getSystemProperty(LoggingSystemProperty.LOG_FILE)) .isEqualTo(this.tempDir + new ApplicationPid().toString() + ".log"); } @@ -529,6 +539,7 @@ class LoggingApplicationListenerTests { multicastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener, "loggingSystem"); + assertThat(loggingSystem).isNotNull(); assertThat(loggingSystem.cleanedUp).isFalse(); multicastEvent(new ApplicationFailedEvent(this.springApplication, new String[0], new GenericApplicationContext(), new Exception())); @@ -547,6 +558,7 @@ class LoggingApplicationListenerTests { .get(); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(listener, "loggingSystem"); + assertThat(loggingSystem).isNotNull(); assertThat(loggingSystem.cleanedUp).isFalse(); WebServerStyleLifecycle lifecycle = context.getBean(WebServerStyleLifecycle.class); AtomicBoolean called = new AtomicBoolean(); @@ -567,7 +579,7 @@ class LoggingApplicationListenerTests { propertySources .addFirst(new MapPropertySource("test1", Collections.singletonMap("logging.level.ROOT", "DEBUG"))); propertySources.addLast(new MapPropertySource("test2", Collections.singletonMap("logging.level.root", "WARN"))); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); this.logger.debug("testatdebug"); assertThat(this.output).contains("testatdebug"); } @@ -575,7 +587,7 @@ class LoggingApplicationListenerTests { @Test void loggingGroupsDefaultsAreApplied() { addPropertiesToEnvironment(this.context, "logging.level.web=TRACE"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertTraceEnabled("org.springframework.core", false); assertTraceEnabled("org.springframework.core.codec", true); assertTraceEnabled("org.springframework.http", true); @@ -588,12 +600,18 @@ class LoggingApplicationListenerTests { void loggingGroupsCanBeDefined() { addPropertiesToEnvironment(this.context, "logging.group.foo=com.foo.bar,com.foo.baz", "logging.level.foo=TRACE"); - this.listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); + this.listener.initialize(this.context.getEnvironment(), getClassLoader()); assertTraceEnabled("com.foo", false); assertTraceEnabled("com.foo.bar", true); assertTraceEnabled("com.foo.baz", true); } + private ClassLoader getClassLoader() { + ClassLoader classLoader = this.context.getClassLoader(); + assertThat(classLoader).isNotNull(); + return classLoader; + } + private String getSystemProperty(LoggingSystemProperty property) { return System.getProperty(property.getEnvironmentVariableName()); } @@ -636,7 +654,7 @@ class LoggingApplicationListenerTests { static class TestShutdownHandlerLoggingSystem extends AbstractLoggingSystem { - private static CountDownLatch shutdownLatch; + private static @Nullable CountDownLatch shutdownLatch; TestShutdownHandlerLoggingSystem(ClassLoader classLoader) { super(classLoader); @@ -649,38 +667,42 @@ class LoggingApplicationListenerTests { } @Override - protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { + protected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) { } @Override protected void loadConfiguration(LoggingInitializationContext initializationContext, String location, - LogFile logFile) { + @Nullable LogFile logFile) { } @Override - public void setLogLevel(String loggerName, LogLevel level) { + public void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) { } @Override public List getLoggerConfigurations() { - return null; + return Collections.emptyList(); } @Override - public LoggerConfiguration getLoggerConfiguration(String loggerName) { + public @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) { return null; } @Override public Runnable getShutdownHandler() { - return () -> TestShutdownHandlerLoggingSystem.shutdownLatch.countDown(); + return () -> { + CountDownLatch shutdownLatch = TestShutdownHandlerLoggingSystem.shutdownLatch; + assertThat(shutdownLatch).isNotNull(); + shutdownLatch.countDown(); + }; } } static class TestLoggingApplicationListener extends LoggingApplicationListener { - private Runnable shutdownHook; + private @Nullable Runnable shutdownHook; @Override void registerShutdownHook(Runnable shutdownHook) { @@ -701,16 +723,16 @@ class LoggingApplicationListenerTests { } @Override - public void setLogLevel(String loggerName, LogLevel level) { + public void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) { } @Override public List getLoggerConfigurations() { - return null; + return Collections.emptyList(); } @Override - public LoggerConfiguration getLoggerConfiguration(String loggerName) { + public @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) { return null; } @@ -732,22 +754,22 @@ class LoggingApplicationListenerTests { } @Override - public void initialize(LoggingInitializationContext initializationContext, String configLocation, - LogFile logFile) { + public void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation, + @Nullable LogFile logFile) { throw new Error("Deliberately broken"); } @Override - public void setLogLevel(String loggerName, LogLevel level) { + public void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) { } @Override public List getLoggerConfigurations() { - return null; + return Collections.emptyList(); } @Override - public LoggerConfiguration getLoggerConfiguration(String loggerName) { + public @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) { return null; } @@ -763,7 +785,7 @@ class LoggingApplicationListenerTests { private volatile boolean running; - Runnable onStop; + @Nullable Runnable onStop; @Override public void start() { @@ -773,7 +795,9 @@ class LoggingApplicationListenerTests { @Override public void stop() { this.running = false; - this.onStop.run(); + if (this.onStop != null) { + this.onStop.run(); + } } @Override diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java index 23d8b67ec75..ae0e61fc5b8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java @@ -21,6 +21,7 @@ import java.util.stream.Stream; import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AssertProvider; import org.assertj.core.error.BasicErrorMessageFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.TypeHint; @@ -28,6 +29,7 @@ import org.springframework.aot.hint.TypeReference; import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.factory.aot.AotServices; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.context.properties.ConfigurationPropertiesBeanFactoryInitializationAotProcessor.ConfigurationPropertiesReflectionHintsContribution; @@ -38,6 +40,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link ConfigurationPropertiesBeanFactoryInitializationAotProcessor}. @@ -67,6 +70,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton("test", new SampleProperties()); ConfigurationPropertiesReflectionHintsContribution contribution = process(beanFactory); + assertThat(contribution).isNotNull(); assertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN).hasType(SampleProperties.class); assertThat(typeHints(contribution).map(TypeHint::getType)) .containsExactly(TypeReference.of(SampleProperties.class)); @@ -75,6 +79,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { @Test void javaBeanConfigurationPropertiesBindAsJavaBean() { ConfigurationPropertiesReflectionHintsContribution contribution = process(EnableJavaBeanProperties.class); + assertThat(contribution).isNotNull(); assertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN).hasType(JavaBeanProperties.class); assertThat(typeHints(contribution).map(TypeHint::getType)) .containsExactly(TypeReference.of(JavaBeanProperties.class)); @@ -84,6 +89,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { void constructorBindingConfigurationPropertiesBindAsValueObject() { ConfigurationPropertiesReflectionHintsContribution contribution = process( EnableConstructorBindingProperties.class); + assertThat(contribution).isNotNull(); assertThat(singleBindable(contribution)).hasBindMethod(BindMethod.VALUE_OBJECT) .hasType(ConstructorBindingProperties.class); assertThat(typeHints(contribution).map(TypeHint::getType)) @@ -94,6 +100,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { void possibleConstructorBindingPropertiesDefinedThroughBeanMethodBindAsJavaBean() { ConfigurationPropertiesReflectionHintsContribution contribution = process( PossibleConstructorBindingPropertiesBeanMethodConfiguration.class); + assertThat(contribution).isNotNull(); assertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN) .hasType(PossibleConstructorBindingProperties.class); assertThat(typeHints(contribution).map(TypeHint::getType)) @@ -104,6 +111,7 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { void possibleConstructorBindingPropertiesDefinedThroughEnabledAnnotationBindAsValueObject() { ConfigurationPropertiesReflectionHintsContribution contribution = process( EnablePossibleConstructorBindingProperties.class); + assertThat(contribution).isNotNull(); assertThat(singleBindable(contribution)).hasBindMethod(BindMethod.VALUE_OBJECT) .hasType(PossibleConstructorBindingProperties.class); assertThat(typeHints(contribution).map(TypeHint::getType)) @@ -112,17 +120,18 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { private Stream typeHints(ConfigurationPropertiesReflectionHintsContribution contribution) { TestGenerationContext generationContext = new TestGenerationContext(); - contribution.applyTo(generationContext, null); + contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class)); return generationContext.getRuntimeHints().reflection().typeHints(); } - private ConfigurationPropertiesReflectionHintsContribution process(Class config) { + private @Nullable ConfigurationPropertiesReflectionHintsContribution process(Class config) { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config)) { return process(context.getBeanFactory()); } } - private ConfigurationPropertiesReflectionHintsContribution process(ConfigurableListableBeanFactory beanFactory) { + private @Nullable ConfigurationPropertiesReflectionHintsContribution process( + ConfigurableListableBeanFactory beanFactory) { return this.processor.processAheadOfTime(beanFactory); } @@ -144,13 +153,13 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { @ConfigurationProperties("java-bean") static class JavaBeanProperties { - private String value; + private @Nullable String value; - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } @@ -195,17 +204,17 @@ class ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests { @ConfigurationProperties("possible-constructor-binding") static class PossibleConstructorBindingProperties { - private String value; + private @Nullable String value; PossibleConstructorBindingProperties(String arg) { } - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessorTests.java index 27592b42e60..c96562aca04 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessorTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties; import java.util.Arrays; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aot.test.generate.TestGenerationContext; @@ -81,7 +82,7 @@ class ConfigurationPropertiesBeanRegistrationAotProcessorTests { assertThat(contribution).isNotNull(); } - private BeanRegistrationAotContribution process(Class type) { + private @Nullable BeanRegistrationAotContribution process(Class type) { ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(this.beanFactory); beanRegistrar.register(type); RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, @@ -177,13 +178,13 @@ class ConfigurationPropertiesBeanRegistrationAotProcessorTests { @ConfigurationProperties("test") public static class JavaBeanSampleBean { - private String name; + private @Nullable String name; - public String getName() { + public @Nullable String getName() { return this.name; } - public void setName(String name) { + public void setName(@Nullable String name) { this.name = name; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java index 5dfa2aa0d30..fb6014971c2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java @@ -22,6 +22,7 @@ import java.util.Map; import net.bytebuddy.ByteBuddy; import net.bytebuddy.ClassFileVersion; import net.bytebuddy.description.annotation.AnnotationDescription; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.ThrowingConsumer; @@ -60,18 +61,21 @@ class ConfigurationPropertiesBeanTests { Map all = ConfigurationPropertiesBean.getAll(context); assertThat(all).containsOnlyKeys("annotatedComponent", "annotatedBean", ValueObject.class.getName()); ConfigurationPropertiesBean component = all.get("annotatedComponent"); + assertThat(component).isNotNull(); assertThat(component.getName()).isEqualTo("annotatedComponent"); assertThat(component.getInstance()).isInstanceOf(AnnotatedComponent.class); assertThat(component.getAnnotation()).isNotNull(); assertThat(component.getType()).isEqualTo(AnnotatedComponent.class); assertThat(component.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN); ConfigurationPropertiesBean bean = all.get("annotatedBean"); + assertThat(bean).isNotNull(); assertThat(bean.getName()).isEqualTo("annotatedBean"); assertThat(bean.getInstance()).isInstanceOf(AnnotatedBean.class); assertThat(bean.getType()).isEqualTo(AnnotatedBean.class); assertThat(bean.getAnnotation()).isNotNull(); assertThat(bean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN); ConfigurationPropertiesBean valueObject = all.get(ValueObject.class.getName()); + assertThat(valueObject).isNotNull(); assertThat(valueObject.getName()).isEqualTo(ValueObject.class.getName()); assertThat(valueObject.getInstance()).isInstanceOf(ValueObject.class); assertThat(valueObject.getType()).isEqualTo(ValueObject.class); @@ -157,6 +161,7 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasFactoryMethodBindsUsingMethodReturnType() throws Throwable { get(NonAnnotatedGenericBeanConfiguration.class, "nonAnnotatedGenericBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); assertThat(propertiesBean.getType()).isEqualTo(NonAnnotatedGenericBean.class); assertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN); ResolvableType type = propertiesBean.asBindTarget().getType(); @@ -168,6 +173,7 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasFactoryMethodWithoutAnnotationBindsUsingMethodType() throws Throwable { get(AnnotatedGenericBeanConfiguration.class, "annotatedGenericBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); assertThat(propertiesBean.getType()).isEqualTo(AnnotatedGenericBean.class); assertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN); ResolvableType type = propertiesBean.asBindTarget().getType(); @@ -179,6 +185,7 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasNoFactoryMethodBindsUsingObjectType() throws Throwable { get(AnnotatedGenericComponent.class, "annotatedGenericComponent", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); assertThat(propertiesBean.getType()).isEqualTo(AnnotatedGenericComponent.class); assertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN); ResolvableType type = propertiesBean.asBindTarget().getType(); @@ -189,14 +196,18 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasFactoryMethodAndBeanAnnotationFavorsFactoryMethod() throws Throwable { - get(AnnotatedBeanConfiguration.class, "annotatedBean", - (propertiesBean) -> assertThat(propertiesBean.getAnnotation().prefix()).isEqualTo("factory")); + get(AnnotatedBeanConfiguration.class, "annotatedBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); + assertThat(propertiesBean.getAnnotation().prefix()).isEqualTo("factory"); + }); } @Test void getWhenHasValidatedBeanBindsWithBeanAnnotation() throws Throwable { get(ValidatedBeanConfiguration.class, "validatedBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); Validated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class); + assertThat(validated).isNotNull(); assertThat(validated.value()).containsExactly(BeanGroup.class); }); } @@ -204,7 +215,9 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasValidatedFactoryMethodBindsWithFactoryMethodAnnotation() throws Throwable { get(ValidatedMethodConfiguration.class, "annotatedBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); Validated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class); + assertThat(validated).isNotNull(); assertThat(validated.value()).containsExactly(FactoryMethodGroup.class); }); } @@ -212,7 +225,9 @@ class ConfigurationPropertiesBeanTests { @Test void getWhenHasValidatedBeanAndFactoryMethodBindsWithFactoryMethodAnnotation() throws Throwable { get(ValidatedMethodAndBeanConfiguration.class, "validatedBean", (propertiesBean) -> { + assertThat(propertiesBean).isNotNull(); Validated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class); + assertThat(validated).isNotNull(); assertThat(validated.value()).containsExactly(FactoryMethodGroup.class); }); } @@ -336,18 +351,18 @@ class ConfigurationPropertiesBeanTests { assertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN); } - private void get(Class configuration, String beanName, ThrowingConsumer consumer) - throws Throwable { + private void get(Class configuration, String beanName, + ThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable { get(configuration, beanName, true, consumer); } private void getWithoutBeanMetadataCaching(Class configuration, String beanName, - ThrowingConsumer consumer) throws Throwable { + ThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable { get(configuration, beanName, false, consumer); } private void get(Class configuration, String beanName, boolean cacheBeanMetadata, - ThrowingConsumer consumer) throws Throwable { + ThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { context.getBeanFactory().setCacheBeanMetadata(cacheBeanMetadata); context.register(configuration); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindExceptionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindExceptionTests.java index 11ae9186b0e..e8f980f2142 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindExceptionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindExceptionTests.java @@ -36,6 +36,7 @@ class ConfigurationPropertiesBindExceptionTests { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Example.class); ConfigurationPropertiesBean bean = ConfigurationPropertiesBean.get(applicationContext, applicationContext.getBean(Example.class), "example"); + assertThat(bean).isNotNull(); ConfigurationPropertiesBindException exception = new ConfigurationPropertiesBindException(bean, new IllegalStateException()); assertThat(exception.getMessage()).isEqualTo("Error creating bean with name 'example': " diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisorTests.java index 157f5ce07c2..bc201dbf50e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisorTests.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -57,9 +58,11 @@ class ConfigurationPropertiesBindHandlerAdvisorTests { "foo.bar.bindings.output.destination=d2"); BindingServiceProperties properties = this.context.getBean(BindingServiceProperties.class); BindingProperties input = properties.getBindings().get("input"); + assertThat(input).isNotNull(); assertThat(input.getDestination()).isEqualTo("d1"); assertThat(input.getContentType()).isEqualTo("text/xml"); BindingProperties output = properties.getBindings().get("output"); + assertThat(output).isNotNull(); assertThat(output.getDestination()).isEqualTo("d2"); assertThat(output.getContentType()).isEqualTo("application/json"); } @@ -71,9 +74,11 @@ class ConfigurationPropertiesBindHandlerAdvisorTests { "foo.bar.bindings.output.destination=d2"); BindingServiceProperties properties = this.context.getBean(BindingServiceProperties.class); BindingProperties input = properties.getBindings().get("input"); + assertThat(input).isNotNull(); assertThat(input.getDestination()).isEqualTo("d1"); assertThat(input.getContentType()).isEqualTo("text/xml"); BindingProperties output = properties.getBindings().get("output"); + assertThat(output).isNotNull(); assertThat(output.getDestination()).isEqualTo("d2"); assertThat(output.getContentType()).isEqualTo("text/plain"); } @@ -124,7 +129,8 @@ class ConfigurationPropertiesBindHandlerAdvisorTests { } @Override - public Bindable onStart(ConfigurationPropertyName name, Bindable target, BindContext context) { + public @Nullable Bindable onStart(ConfigurationPropertyName name, Bindable target, + BindContext context) { ConfigurationPropertyName defaultName = getDefaultName(name); if (defaultName != null) { BindResult result = context.getBinder().bind(defaultName, target); @@ -135,7 +141,7 @@ class ConfigurationPropertiesBindHandlerAdvisorTests { return super.onStart(name, target, context); } - private ConfigurationPropertyName getDefaultName(ConfigurationPropertyName name) { + private @Nullable ConfigurationPropertyName getDefaultName(ConfigurationPropertyName name) { for (Map.Entry mapping : this.mappings.entrySet()) { ConfigurationPropertyName from = mapping.getKey(); ConfigurationPropertyName to = mapping.getValue(); @@ -161,15 +167,15 @@ class ConfigurationPropertiesBindHandlerAdvisorTests { static class BindingProperties { - private String destination; + private @Nullable String destination; private String contentType = "application/json"; - String getDestination() { + @Nullable String getDestination() { return this.destination; } - void setDestination(String destination) { + void setDestination(@Nullable String destination) { this.destination = destination; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java index b51dbd566cc..d5a1f3bf110 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties; import java.io.IOException; import java.util.Objects; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -151,7 +152,7 @@ class ConfigurationPropertiesScanTests { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { return (this == o); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTestBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTestBeanTests.java index 8963b5b3aae..dfa74d707b3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTestBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTestBeanTests.java @@ -37,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; class ConfigurationPropertiesTestBeanTests { @TestBean + @SuppressWarnings("NullAway.Init") private ImmutableProperties properties; @Autowired diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java index 568295ca18e..9dfb957b7cf 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java @@ -38,6 +38,7 @@ import jakarta.annotation.PostConstruct; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -56,6 +57,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.SpringApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesTests.JavaBeanNestedConstructorBindingProperties.Nested; import org.springframework.boot.context.properties.bind.BindException; import org.springframework.boot.context.properties.bind.ConstructorBinding; import org.springframework.boot.context.properties.bind.DefaultValue; @@ -368,7 +370,9 @@ class ConfigurationPropertiesTests { void loadShouldBindToJavaTimeDuration() { load(BasicConfiguration.class, "duration=PT1M"); BasicProperties bean = this.context.getBean(BasicProperties.class); - assertThat(bean.getDuration().getSeconds()).isEqualTo(60); + Duration duration = bean.getDuration(); + assertThat(duration).isNotNull(); + assertThat(duration.getSeconds()).isEqualTo(60); } @Test @@ -480,7 +484,9 @@ class ConfigurationPropertiesTests { void loadShouldBindToMapWithNumericKey() { load(MapWithNumericKeyProperties.class, "sample.properties.1.name=One"); MapWithNumericKeyProperties bean = this.context.getBean(MapWithNumericKeyProperties.class); - assertThat(bean.getProperties().get("1").name).isEqualTo("One"); + BasicProperties one = bean.getProperties().get("1"); + assertThat(one).isNotNull(); + assertThat(one.name).isEqualTo("One"); } @Test @@ -491,8 +497,10 @@ class ConfigurationPropertiesTests { Collections.singletonMap("TEST_MAP_FOO_BAR", "baz"))); load(WithComplexMapProperties.class); WithComplexMapProperties bean = this.context.getBean(WithComplexMapProperties.class); - assertThat(bean.getMap()).containsOnlyKeys("foo"); - assertThat(bean.getMap().get("foo")).containsOnly(entry("bar", "baz")); + Map> map = bean.getMap(); + assertThat(map).isNotNull(); + assertThat(map).containsOnlyKeys("foo"); + assertThat(map.get("foo")).containsOnly(entry("bar", "baz")); } @Test @@ -692,6 +700,7 @@ class ConfigurationPropertiesTests { void loadShouldUseConverterBean() { prepareConverterContext(PersonConverterConfiguration.class, PersonProperties.class); Person person = this.context.getBean(PersonProperties.class).getPerson(); + assertThat(person).isNotNull(); assertThat(person.firstName).isEqualTo("John"); assertThat(person.lastName).isEqualTo("Smith"); } @@ -727,6 +736,7 @@ class ConfigurationPropertiesTests { this.context.getEnvironment().getPropertySources().addLast(testProperties); this.context.refresh(); Person person = this.context.getBean(PersonProperties.class).getPerson(); + assertThat(person).isNotNull(); assertThat(person.firstName).isEqualTo("John"); assertThat(person.lastName).isEqualTo("Smith"); } @@ -739,9 +749,13 @@ class ConfigurationPropertiesTests { load(new Class[] { PersonConverterConfiguration.class, PersonAndAlienProperties.class }, "test.person=John Smith", "test.alien=Alf Tanner"); PersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class); - assertThat(properties.getPerson().firstName).isEqualTo("John"); - assertThat(properties.getPerson().lastName).isEqualTo("Smith"); - assertThat(properties.getAlien().name).isEqualTo("rennaT flA"); + Person person = properties.getPerson(); + assertThat(person).isNotNull(); + assertThat(person.firstName).isEqualTo("John"); + assertThat(person.lastName).isEqualTo("Smith"); + Alien alien = properties.getAlien(); + assertThat(alien).isNotNull(); + assertThat(alien.name).isEqualTo("rennaT flA"); } @Test @@ -752,9 +766,13 @@ class ConfigurationPropertiesTests { load(new Class[] { AlienConverterConfiguration.class, PersonAndAlienProperties.class }, "test.person=John Smith", "test.alien=Alf Tanner"); PersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class); - assertThat(properties.getPerson().firstName).isEqualTo("John"); - assertThat(properties.getPerson().lastName).isEqualTo("Smith"); - assertThat(properties.getAlien().name).isEqualTo("rennaT flA"); + Person person = properties.getPerson(); + assertThat(person).isNotNull(); + assertThat(person.firstName).isEqualTo("John"); + assertThat(person.lastName).isEqualTo("Smith"); + Alien alien = properties.getAlien(); + assertThat(alien).isNotNull(); + assertThat(alien.name).isEqualTo("rennaT flA"); } @Test // gh-38734 @@ -765,10 +783,14 @@ class ConfigurationPropertiesTests { load(new Class[] { AlienConverterConfiguration.class, PersonAndAliensProperties.class }, "test.person=John Smith", "test.aliens=Alf Tanner,Gilbert"); PersonAndAliensProperties properties = this.context.getBean(PersonAndAliensProperties.class); - assertThat(properties.getPerson().firstName).isEqualTo("John"); - assertThat(properties.getPerson().lastName).isEqualTo("Smith"); - assertThat(properties.getAliens().get(0).name).isEqualTo("rennaT flA"); - assertThat(properties.getAliens().get(1).name).isEqualTo("trebliG"); + Person person = properties.getPerson(); + assertThat(person).isNotNull(); + assertThat(person.firstName).isEqualTo("John"); + assertThat(person.lastName).isEqualTo("Smith"); + List aliens = properties.getAliens(); + assertThat(aliens).isNotNull(); + assertThat(aliens.get(0).name).isEqualTo("rennaT flA"); + assertThat(aliens.get(1).name).isEqualTo("trebliG"); } @Test @@ -782,6 +804,7 @@ class ConfigurationPropertiesTests { void loadShouldUseGenericConverterBean() { prepareConverterContext(GenericConverterConfiguration.class, PersonProperties.class); Person person = this.context.getBean(PersonProperties.class).getPerson(); + assertThat(person).isNotNull(); assertThat(person.firstName).isEqualTo("John"); assertThat(person.lastName).isEqualTo("Smith"); } @@ -790,6 +813,7 @@ class ConfigurationPropertiesTests { void loadShouldUseFormatterBean() { prepareConverterContext(FormatterConfiguration.class, PersonProperties.class); Person person = this.context.getBean(PersonProperties.class).getPerson(); + assertThat(person).isNotNull(); assertThat(person.firstName).isEqualTo("John"); assertThat(person.lastName).isEqualTo("Smith"); } @@ -875,8 +899,10 @@ class ConfigurationPropertiesTests { this.context.getBeanFactory().registerCustomEditor(Person.class, PersonPropertyEditor.class); load(PersonProperties.class, "test.person=boot,spring"); PersonProperties bean = this.context.getBean(PersonProperties.class); - assertThat(bean.getPerson().firstName).isEqualTo("spring"); - assertThat(bean.getPerson().lastName).isEqualTo("boot"); + Person person = bean.getPerson(); + assertThat(person).isNotNull(); + assertThat(person.firstName).isEqualTo("spring"); + assertThat(person.lastName).isEqualTo("boot"); } @Test @@ -918,11 +944,18 @@ class ConfigurationPropertiesTests { sources.addLast(new MapPropertySource("test", source)); load(WithIntegerMapProperties.class); WithIntegerMapProperties bean = this.context.getBean(WithIntegerMapProperties.class); - Map x = bean.getMap().get("x"); - assertThat(x.get(-1).getA()).isEqualTo("baz"); - assertThat(x.get(-1).getB()).isZero(); - assertThat(x.get(1).getA()).isEqualTo("bar"); - assertThat(x.get(1).getB()).isOne(); + Map> map = bean.getMap(); + assertThat(map).isNotNull(); + Map x = map.get("x"); + assertThat(x).isNotNull(); + Foo minus1 = x.get(-1); + assertThat(minus1).isNotNull(); + assertThat(minus1.getA()).isEqualTo("baz"); + assertThat(minus1.getB()).isZero(); + Foo one = x.get(1); + assertThat(one).isNotNull(); + assertThat(one.getA()).isEqualTo("bar"); + assertThat(one.getB()).isOne(); } @Test @@ -1133,7 +1166,9 @@ class ConfigurationPropertiesTests { load(JavaBeanNestedConstructorBindingPropertiesConfiguration.class); JavaBeanNestedConstructorBindingProperties bean = this.context .getBean(JavaBeanNestedConstructorBindingProperties.class); - assertThat(bean.getNested().getAge()).isEqualTo(5); + Nested nested = bean.getNested(); + assertThat(nested).isNotNull(); + assertThat(nested.getAge()).isEqualTo(5); } @Test @@ -1156,7 +1191,9 @@ class ConfigurationPropertiesTests { load(JavaBeanNonDefaultConstructorPropertiesConfiguration.class); JavaBeanNonDefaultConstructorProperties bean = this.context .getBean(JavaBeanNonDefaultConstructorProperties.class); - assertThat(bean.getNested().getAge()).isEqualTo(10); + JavaBeanNonDefaultConstructorProperties.Nested nested = bean.getNested(); + assertThat(nested).isNotNull(); + assertThat(nested.getAge()).isEqualTo(10); } @Test // gh-18652 @@ -1177,7 +1214,9 @@ class ConfigurationPropertiesTests { load(ConstructorBindingWithOuterClassConstructorBoundConfiguration.class); ConstructorBindingWithOuterClassConstructorBoundProperties bean = this.context .getBean(ConstructorBindingWithOuterClassConstructorBoundProperties.class); - assertThat(bean.getNested().getOuter().getAge()).isEqualTo(5); + Outer outer = bean.getNested().getOuter(); + assertThat(outer).isNotNull(); + assertThat(outer.getAge()).isEqualTo(5); } @Test @@ -1218,6 +1257,7 @@ class ConfigurationPropertiesTests { void boundPropertiesShouldBeRecorded() { load(NestedConfiguration.class, "name=foo", "nested.name=bar"); BoundConfigurationProperties bound = BoundConfigurationProperties.get(this.context); + assertThat(bound).isNotNull(); Set keys = bound.getAll().keySet(); assertThat(keys.stream().map(ConfigurationPropertyName::toString)).contains("name", "nested.name"); } @@ -1228,7 +1268,9 @@ class ConfigurationPropertiesTests { load(WithCustomConverterAndObjectToObjectMethodConfiguration.class, "test.item=foo"); WithCustomConverterAndObjectToObjectMethodProperties bean = this.context .getBean(WithCustomConverterAndObjectToObjectMethodProperties.class); - assertThat(bean.getItem().getValue()).isEqualTo("foo"); + WithPublicObjectToObjectMethod item = bean.getItem(); + assertThat(item).isNotNull(); + assertThat(item.getValue()).isEqualTo("foo"); } @Test // gh-33710 @@ -1465,15 +1507,15 @@ class ConfigurationPropertiesTests { @ConfigurationProperties static class WithPostConstructConfiguration { - private String bar; + private @Nullable String bar; private boolean initialized; - void setBar(String bar) { + void setBar(@Nullable String bar) { this.bar = bar; } - String getBar() { + @Nullable String getBar() { return this.bar; } @@ -1564,13 +1606,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class PropertiesWithResource { - private Resource resource; + private @Nullable Resource resource; - Resource getResource() { + @Nullable Resource getResource() { return this.resource; } - void setResource(Resource resource) { + void setResource(@Nullable Resource resource) { this.resource = resource; } @@ -1581,7 +1623,7 @@ class ConfigurationPropertiesTests { static final String PREFIX = "test:/"; @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { + public @Nullable Resource resolve(String location, ResourceLoader resourceLoader) { if (location.startsWith(PREFIX)) { String path = location.substring(PREFIX.length()); return new ClassPathResource(path); @@ -1691,13 +1733,13 @@ class ConfigurationPropertiesTests { static class AGenericClass { - private T bar; + private @Nullable T bar; - T getBar() { + @Nullable T getBar() { return this.bar; } - void setBar(T bar) { + void setBar(@Nullable T bar) { this.bar = bar; } @@ -1705,23 +1747,23 @@ class ConfigurationPropertiesTests { static class PrototypeBean { - private String one; + private @Nullable String one; - private String two; + private @Nullable String two; - String getOne() { + @Nullable String getOne() { return this.one; } - void setOne(String one) { + void setOne(@Nullable String one) { this.one = one; } - String getTwo() { + @Nullable String getTwo() { return this.two; } - void setTwo(String two) { + void setTwo(@Nullable String two) { this.two = two; } @@ -1737,7 +1779,7 @@ class ConfigurationPropertiesTests { } @Override - public Class getObjectType() { + public @Nullable Class getObjectType() { return null; } @@ -1756,17 +1798,17 @@ class ConfigurationPropertiesTests { @ConfigurationProperties public static class BasicProperties { - private String name; + private @Nullable String name; - private int[] array; + private int @Nullable [] array; - private List list = new ArrayList<>(); + private @Nullable List list = new ArrayList<>(); - private Duration duration; + private @Nullable Duration duration; // No getter - you should be able to bind to a write-only bean - public void setName(String name) { + public void setName(@Nullable String name) { // Must be public for XML this.name = name; } @@ -1775,23 +1817,23 @@ class ConfigurationPropertiesTests { this.array = values; } - int[] getArray() { + int @Nullable [] getArray() { return this.array; } - List getList() { + @Nullable List getList() { return this.list; } - void setList(List list) { + void setList(@Nullable List list) { this.list = list; } - Duration getDuration() { + @Nullable Duration getDuration() { return this.duration; } - void setDuration(Duration duration) { + void setDuration(@Nullable Duration duration) { this.duration = duration; } @@ -1800,11 +1842,11 @@ class ConfigurationPropertiesTests { @ConfigurationProperties static class NestedProperties { - private String name; + private @Nullable String name; private final Nested nested = new Nested(); - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } @@ -1814,9 +1856,9 @@ class ConfigurationPropertiesTests { static class Nested { - private String name; + private @Nullable String name; - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } @@ -1863,6 +1905,7 @@ class ConfigurationPropertiesTests { static class Jsr303Properties extends BasicProperties { @NotEmpty + @SuppressWarnings("NullAway.Init") private String description; String getDescription() { @@ -1920,9 +1963,9 @@ class ConfigurationPropertiesTests { @ConfigurationProperties static class WithoutAnnotationValueProperties { - private String name; + private @Nullable String name; - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } @@ -1934,13 +1977,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties static class MapProperties { - private Map mymap; + private @Nullable Map mymap; - void setMymap(Map mymap) { + void setMymap(@Nullable Map mymap) { this.mymap = mymap; } - Map getMymap() { + @Nullable Map getMymap() { return this.mymap; } @@ -1957,7 +2000,7 @@ class ConfigurationPropertiesTests { assertThat(this.properties).isNotNull(); } - String getName() { + @Nullable String getName() { return this.properties.name; } @@ -1974,6 +2017,7 @@ class ConfigurationPropertiesTests { static class ValidatedImplementationProperties implements InterfaceForValidatedImplementation { @NotNull + @SuppressWarnings("NullAway.Init") private String foo; @Override @@ -1992,13 +2036,13 @@ class ConfigurationPropertiesTests { static class WithPropertyPlaceholderValueProperties { @Value("${default.value}") - private String value; + private @Nullable String value; - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } - String getValue() { + @Nullable String getValue() { return this.value; } @@ -2008,23 +2052,23 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithEnumProperties { - private FooEnum theValue; + private @Nullable FooEnum theValue; - private List theValues; + private @Nullable List theValues; - void setTheValue(FooEnum value) { + void setTheValue(@Nullable FooEnum value) { this.theValue = value; } - FooEnum getTheValue() { + @Nullable FooEnum getTheValue() { return this.theValue; } - List getTheValues() { + @Nullable List getTheValues() { return this.theValues; } - void setTheValues(List theValues) { + void setTheValues(@Nullable List theValues) { this.theValues = theValues; } @@ -2040,13 +2084,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties(prefix = "test", ignoreUnknownFields = false) static class WithCharArrayProperties { - private char[] chars; + private char @Nullable [] chars; - char[] getChars() { + char @Nullable [] getChars() { return this.chars; } - void setChars(char[] chars) { + void setChars(char @Nullable [] chars) { this.chars = chars; } @@ -2056,23 +2100,23 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithRelaxedNamesProperties { - private String fooBar; + private @Nullable String fooBar; - private String barBAZ; + private @Nullable String barBAZ; - String getFooBar() { + @Nullable String getFooBar() { return this.fooBar; } - void setFooBar(String fooBar) { + void setFooBar(@Nullable String fooBar) { this.fooBar = fooBar; } - String getBarBAZ() { + @Nullable String getBarBAZ() { return this.barBAZ; } - void setBarBAZ(String barBAZ) { + void setBarBAZ(@Nullable String barBAZ) { this.barBAZ = barBAZ; } @@ -2083,13 +2127,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithMapProperties { - private Map map; + private @Nullable Map map; - Map getMap() { + @Nullable Map getMap() { return this.map; } - void setMap(Map map) { + void setMap(@Nullable Map map) { this.map = map; } @@ -2099,13 +2143,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithComplexMapProperties { - private Map> map; + private @Nullable Map> map; - Map> getMap() { + @Nullable Map> getMap() { return this.map; } - void setMap(Map> map) { + void setMap(@Nullable Map> map) { this.map = map; } @@ -2115,13 +2159,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithIntegerMapProperties { - private Map> map; + private @Nullable Map> map; - Map> getMap() { + @Nullable Map> getMap() { return this.map; } - void setMap(Map> map) { + void setMap(@Nullable Map> map) { this.map = map; } @@ -2133,13 +2177,13 @@ class ConfigurationPropertiesTests { private int foo; - private String bar; + private @Nullable String bar; - String getBar() { + @Nullable String getBar() { return this.bar; } - void setBar(String bar) { + void setBar(@Nullable String bar) { this.bar = bar; } @@ -2157,13 +2201,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class PersonProperties { - private Person person; + private @Nullable Person person; - Person getPerson() { + @Nullable Person getPerson() { return this.person; } - void setPerson(Person person) { + void setPerson(@Nullable Person person) { this.person = person; } @@ -2173,23 +2217,23 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class PersonAndAlienProperties { - private Person person; + private @Nullable Person person; - private Alien alien; + private @Nullable Alien alien; - Person getPerson() { + @Nullable Person getPerson() { return this.person; } - void setPerson(Person person) { + void setPerson(@Nullable Person person) { this.person = person; } - Alien getAlien() { + @Nullable Alien getAlien() { return this.alien; } - void setAlien(Alien alien) { + void setAlien(@Nullable Alien alien) { this.alien = alien; } @@ -2199,23 +2243,23 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class PersonAndAliensProperties { - private Person person; + private @Nullable Person person; - private List aliens; + private @Nullable List aliens; - Person getPerson() { + @Nullable Person getPerson() { return this.person; } - void setPerson(Person person) { + void setPerson(@Nullable Person person) { this.person = person; } - List getAliens() { + @Nullable List getAliens() { return this.aliens; } - void setAliens(List aliens) { + void setAliens(@Nullable List aliens) { this.aliens = aliens; } @@ -2237,7 +2281,7 @@ class ConfigurationPropertiesTests { @ConfigurationProperties static class ValidatorProperties implements Validator { - private String foo; + private @Nullable String foo; @Override public boolean supports(Class type) { @@ -2249,11 +2293,11 @@ class ConfigurationPropertiesTests { ValidationUtils.rejectIfEmpty(errors, "foo", "TEST1"); } - String getFoo() { + @Nullable String getFoo() { return this.foo; } - void setFoo(String foo) { + void setFoo(@Nullable String foo) { this.foo = foo; } @@ -2293,9 +2337,9 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithSetterThatThrowsValidationExceptionProperties { - private String foo; + private @Nullable String foo; - String getFoo() { + @Nullable String getFoo() { return this.foo; } @@ -2311,13 +2355,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("custom") static class WithCustomValidatorProperties { - private String foo; + private @Nullable String foo; - String getFoo() { + @Nullable String getFoo() { return this.foo; } - void setFoo(String foo) { + void setFoo(@Nullable String foo) { this.foo = foo; } @@ -2327,13 +2371,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class ListOfGenericClassProperties { - private List> list; + private @Nullable List> list; - List> getList() { + @Nullable List> getList() { return this.list; } - void setList(List> list) { + void setList(@Nullable List> list) { this.list = list; } @@ -2343,13 +2387,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class FileProperties { - private File file; + private @Nullable File file; - File getFile() { + @Nullable File getFile() { return this.file; } - void setFile(File file) { + void setFile(@Nullable File file) { this.file = file; } @@ -2359,24 +2403,24 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class DataSizeProperties { - private DataSize size; + private @Nullable DataSize size; @DataSizeUnit(DataUnit.KILOBYTES) - private DataSize anotherSize; + private @Nullable DataSize anotherSize; - DataSize getSize() { + @Nullable DataSize getSize() { return this.size; } - void setSize(DataSize size) { + void setSize(@Nullable DataSize size) { this.size = size; } - DataSize getAnotherSize() { + @Nullable DataSize getAnotherSize() { return this.anotherSize; } - void setAnotherSize(DataSize anotherSize) { + void setAnotherSize(@Nullable DataSize anotherSize) { this.anotherSize = anotherSize; } @@ -2385,7 +2429,7 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class OtherInjectedProperties { - final DataSizeProperties dataSizeProperties; + final @Nullable DataSizeProperties dataSizeProperties; OtherInjectedProperties(ObjectProvider dataSizeProperties) { this.dataSizeProperties = dataSizeProperties.getIfUnique(); @@ -2578,6 +2622,7 @@ class ConfigurationPropertiesTests { @Override public Person convert(String source) { String[] content = StringUtils.split(source, " "); + assertThat(content).isNotNull(); return new Person(content[0], content[1]); } @@ -2600,8 +2645,9 @@ class ConfigurationPropertiesTests { } @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { String[] content = StringUtils.split((String) source, " "); + assertThat(content).isNotNull(); return new Person(content[0], content[1]); } @@ -2669,15 +2715,15 @@ class ConfigurationPropertiesTests { static class Foo { - private String a; + private @Nullable String a; private int b; - String getA() { + @Nullable String getA() { return this.a; } - void setA(String a) { + void setA(@Nullable String a) { this.a = a; } @@ -2796,13 +2842,13 @@ class ConfigurationPropertiesTests { static class Nested { - private Outer outer; + private @Nullable Outer outer; - Outer getOuter() { + @Nullable Outer getOuter() { return this.outer; } - void setOuter(Outer nested) { + void setOuter(@Nullable Outer nested) { this.outer = nested; } @@ -2890,13 +2936,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class JavaBeanNestedConstructorBindingProperties { - private Nested nested; + private @Nullable Nested nested; - Nested getNested() { + @Nullable Nested getNested() { return this.nested; } - void setNested(Nested nested) { + void setNested(@Nullable Nested nested) { this.nested = nested; } @@ -2926,13 +2972,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class JavaBeanNonDefaultConstructorProperties { - private Nested nested; + private @Nullable Nested nested; - Nested getNested() { + @Nullable Nested getNested() { return this.nested; } - void setNested(Nested nested) { + void setNested(@Nullable Nested nested) { this.nested = nested; } @@ -3076,13 +3122,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class WithCustomConverterAndObjectToObjectMethodProperties { - private WithPublicObjectToObjectMethod item; + private @Nullable WithPublicObjectToObjectMethod item; - WithPublicObjectToObjectMethod getItem() { + @Nullable WithPublicObjectToObjectMethod getItem() { return this.item; } - void setItem(WithPublicObjectToObjectMethod item) { + void setItem(@Nullable WithPublicObjectToObjectMethod item) { this.item = item; } @@ -3199,17 +3245,17 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class PotentiallyConstructorBoundProperties { - private String prop; + private @Nullable String prop; PotentiallyConstructorBoundProperties(String notAProperty) { } - String getProp() { + @Nullable String getProp() { return this.prop; } - void setProp(String prop) { + void setProp(@Nullable String prop) { this.prop = prop; } @@ -3223,13 +3269,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class ResourceArrayProperties { - private Resource[] resources; + private Resource @Nullable [] resources; - Resource[] getResources() { + Resource @Nullable [] getResources() { return this.resources; } - void setResources(Resource[] resources) { + void setResources(Resource @Nullable [] resources) { this.resources = resources; } @@ -3243,13 +3289,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class ResourceCollectionProperties { - private Collection resources; + private @Nullable Collection resources; - Collection getResources() { + @Nullable Collection getResources() { return this.resources; } - void setResources(Collection resources) { + void setResources(@Nullable Collection resources) { this.resources = resources; } @@ -3311,13 +3357,13 @@ class ConfigurationPropertiesTests { @ConfigurationProperties("test") static class SetterBoundCustomListProperties { - private CustomList values; + private @Nullable CustomList values; - CustomList getValues() { + @Nullable CustomList getValues() { return this.values; } - void setValues(CustomList values) { + void setValues(@Nullable CustomList values) { this.values = values; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConversionServiceDeducerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConversionServiceDeducerTests.java index 134bfaa6124..84cf81305b9 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConversionServiceDeducerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConversionServiceDeducerTests.java @@ -70,6 +70,7 @@ class ConversionServiceDeducerTests { applicationContext.getBeanFactory().setConversionService(conversionService); ConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext); List conversionServices = deducer.getConversionServices(); + assertThat(conversionServices).isNotNull(); assertThat(conversionServices).containsOnly(conversionService); assertThat(conversionServices.get(0)).isSameAs(conversionService); } @@ -106,6 +107,7 @@ class ConversionServiceDeducerTests { ConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext); List conversionServices = deducer.getConversionServices(); InputStream inputStream = new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8)); + assertThat(conversionServices).isNotNull(); assertThat(conversionServices.get(0).convert(inputStream, String.class)).isEqualTo("test"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzerTests.java index c25141dd8ac..0412f6b8dd6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.context.properties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.diagnostics.FailureAnalysis; @@ -32,13 +33,14 @@ class IncompatibleConfigurationFailureAnalyzerTests { @Test void incompatibleConfigurationListsKeys() { FailureAnalysis failureAnalysis = performAnalysis("spring.first.key", "spring.second.key"); + assertThat(failureAnalysis).isNotNull(); assertThat(failureAnalysis.getDescription()).contains( "The following configuration properties have incompatible values: [spring.first.key, spring.second.key]"); assertThat(failureAnalysis.getAction()) .contains("Review the docs for spring.first.key, spring.second.key and change the configured values."); } - private FailureAnalysis performAnalysis(String... keys) { + private @Nullable FailureAnalysis performAnalysis(String... keys) { IncompatibleConfigurationException failure = new IncompatibleConfigurationException(keys); return new IncompatibleConfigurationFailureAnalyzer().analyze(failure); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/MultiConstructorConfigurationProperties.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/MultiConstructorConfigurationProperties.java index f8d6d5a985b..362b9dbd58c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/MultiConstructorConfigurationProperties.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/MultiConstructorConfigurationProperties.java @@ -16,6 +16,8 @@ package org.springframework.boot.context.properties; +import org.jspecify.annotations.Nullable; + /** * Class used to test multi-constructor binding. Must be public and have public * constructors. @@ -24,7 +26,7 @@ package org.springframework.boot.context.properties; */ public class MultiConstructorConfigurationProperties { - private String name; + private @Nullable String name; private int age; @@ -35,11 +37,11 @@ public class MultiConstructorConfigurationProperties { this.name = name; } - public String getName() { + public @Nullable String getName() { return this.name; } - public void setName(String name) { + public void setName(@Nullable String name) { this.name = name; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzerTests.java index 7cf2bb2dc6c..e8526670a88 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.context.properties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.FatalBeanException; @@ -42,6 +43,7 @@ class NotConstructorBoundInjectionFailureAnalyzerTests { void failureAnalysisForConfigurationPropertiesThatShouldHaveBeenConstructorBound() { FailureAnalysis analysis = analyzeFailure( createFailure(ShouldHaveUsedConstructorBindingPropertiesConfiguration.class)); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).isEqualTo(ConstructorBoundProperties.class.getSimpleName() + " is annotated with @" + ConstructorBinding.class.getSimpleName() + " but it is defined as a regular bean which caused dependency injection to fail."); @@ -57,7 +59,7 @@ class NotConstructorBoundInjectionFailureAnalyzerTests { assertThat(analysis).isNull(); } - private FatalBeanException createFailure(Class config) { + private @Nullable FatalBeanException createFailure(Class config) { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { context.register(config); context.refresh(); @@ -68,7 +70,7 @@ class NotConstructorBoundInjectionFailureAnalyzerTests { } } - private FailureAnalysis analyzeFailure(Exception failure) { + private @Nullable FailureAnalysis analyzeFailure(@Nullable Exception failure) { assertThat(failure).isNotNull(); FailureAnalysis analysis = this.analyzer.analyze(failure); if (analysis != null) { @@ -101,18 +103,18 @@ class NotConstructorBoundInjectionFailureAnalyzerTests { @ConfigurationProperties("test") static class JavaBeanBoundProperties { - private String name; + private @Nullable String name; @Autowired JavaBeanBoundProperties(String dependency) { } - String getName() { + @Nullable String getName() { return this.name; } - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java index a0bb86563be..7a822dff938 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.assertj.core.api.Assertions; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -63,6 +64,7 @@ class PropertyMapperTests { } @Test + @SuppressWarnings("NullAway") // Test null check void fromWhenSupplierIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> this.map.from((Supplier) null)) .withMessageContaining("'supplier' must not be null"); @@ -80,6 +82,7 @@ class PropertyMapperTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toWhenConsumerIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> this.map.from(() -> "").to(null)) .withMessageContaining("'consumer' must not be null"); @@ -100,6 +103,7 @@ class PropertyMapperTests { } @Test + @SuppressWarnings("NullAway") // Test null check void asWhenAdapterIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> this.map.from(() -> "").as(null)) .withMessageContaining("'adapter' must not be null"); @@ -262,7 +266,10 @@ class PropertyMapperTests { @Test void asWhenNull() { - String value = this.map.from((String) null).always().as(String::valueOf).toInstance((string) -> string); + String value = this.map.from((String) null).always().as(String::valueOf).toInstance((string) -> { + assertThat(string).isNotNull(); + return string; + }); assertThat(value).isEqualTo("null"); } @@ -336,16 +343,16 @@ class PropertyMapperTests { static class ExampleDest { - private String name; + private @Nullable String name; boolean setNameCalled; - void setName(String name) { + void setName(@Nullable String name) { this.name = name; this.setNameCalled = true; } - String getName() { + @Nullable String getName() { return this.name; } @@ -355,21 +362,21 @@ class PropertyMapperTests { private final String name; - private final Integer age; + private final @Nullable Integer age; final boolean withAgeCalled; - Immutable(String name, Integer age) { + Immutable(String name, @Nullable Integer age) { this(name, age, false); } - private Immutable(String name, Integer age, boolean withAgeCalled) { + private Immutable(String name, @Nullable Integer age, boolean withAgeCalled) { this.name = name; this.age = age; this.withAgeCalled = withAgeCalled; } - Immutable withAge(Integer age) { + Immutable withAge(@Nullable Integer age) { return new Immutable(this.name, age, true); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicStringConstructorProperties.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicStringConstructorProperties.java index afeae0521b4..ec014c1067c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicStringConstructorProperties.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicStringConstructorProperties.java @@ -16,6 +16,8 @@ package org.springframework.boot.context.properties; +import org.jspecify.annotations.Nullable; + /** * A {@link ConfigurationProperties @ConfigurationProperties} with an additional * single-arg public constructor. Used in {@link ConfigurationPropertiesTests}. @@ -25,7 +27,7 @@ package org.springframework.boot.context.properties; @ConfigurationProperties("test") public class WithPublicStringConstructorProperties { - private String a; + private @Nullable String a; public WithPublicStringConstructorProperties() { } @@ -34,11 +36,11 @@ public class WithPublicStringConstructorProperties { this.a = a; } - public String getA() { + public @Nullable String getA() { return this.a; } - public void setA(String a) { + public void setA(@Nullable String a) { this.a = a; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ArrayBinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ArrayBinderTests.java index e5ca058ccf0..b148faae833 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ArrayBinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ArrayBinderTests.java @@ -142,7 +142,9 @@ class ArrayBinderTests { this.sources.add(source); assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind("foo", INTEGER_ARRAY)) .satisfies((ex) -> { - Set unbound = ((UnboundConfigurationPropertiesException) ex.getCause()) + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + Set unbound = ((UnboundConfigurationPropertiesException) cause) .getUnboundProperties(); assertThat(unbound).hasSize(1); ConfigurationProperty property = unbound.iterator().next(); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BackCompatibilityBinderIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BackCompatibilityBinderIntegrationTests.java index 2c527a08e8e..1425772f28d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BackCompatibilityBinderIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BackCompatibilityBinderIntegrationTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.properties.bind; import java.util.Collections; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.core.env.StandardEnvironment; @@ -60,13 +61,13 @@ class BackCompatibilityBinderIntegrationTests { static class ExampleCamelCaseBean { - private String zkNodes; + private @Nullable String zkNodes; - String getZkNodes() { + @Nullable String getZkNodes() { return this.zkNodes; } - void setZkNodes(String zkNodes) { + void setZkNodes(@Nullable String zkNodes) { this.zkNodes = zkNodes; } @@ -74,13 +75,13 @@ class BackCompatibilityBinderIntegrationTests { static class PasswordProperties { - private String password; + private @Nullable String password; - String getPassword() { + @Nullable String getPassword() { return this.password; } - void setPassword(String password) { + void setPassword(@Nullable String password) { this.password = password; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java index 17cbaa7e394..c6ea1c227c8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -53,6 +54,7 @@ import static org.mockito.BDDMockito.then; class BindConverterTests { @Mock + @SuppressWarnings("NullAway.Init") private Consumer propertyEditorInitializer; @Test @@ -121,6 +123,7 @@ class BindConverterTests { void convertWhenHasCustomEditorShouldConvert() { BindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor); SampleType converted = bindConverter.convert("test", ResolvableType.forClass(SampleType.class)); + assertThat(converted).isNotNull(); assertThat(converted.getText()).isEqualTo("test"); } @@ -128,6 +131,7 @@ class BindConverterTests { void convertWhenHasEditorByConventionShouldConvert() { BindConverter bindConverter = getPropertyEditorOnlyBindConverter(null); ConventionType converted = bindConverter.convert("test", ResolvableType.forClass(ConventionType.class)); + assertThat(converted).isNotNull(); assertThat(converted.getText()).isEqualTo("test"); } @@ -144,6 +148,7 @@ class BindConverterTests { void convertWhenHasEditorForArrayElementShouldConvert() { BindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor); SampleType[] converted = bindConverter.convert("test", ResolvableType.forClass(SampleType[].class)); + assertThat(converted).isNotNull(); assertThat(converted).isNotEmpty(); assertThat(converted[0].getText()).isEqualTo("test"); } @@ -152,6 +157,7 @@ class BindConverterTests { void convertWhenConversionServiceCanConvertShouldConvert() { BindConverter bindConverter = getBindConverter(new SampleTypeConverter()); SampleType converted = bindConverter.convert("test", ResolvableType.forClass(SampleType.class)); + assertThat(converted).isNotNull(); assertThat(converted.getText()).isEqualTo("test"); } @@ -169,6 +175,7 @@ class BindConverterTests { BindConverter bindConverter = BindConverter.get(Collections.singletonList(new GenericConversionService()), null); File result = bindConverter.convert(".", ResolvableType.forClass(File.class)); + assertThat(result).isNotNull(); assertThat(result.getPath()).isEqualTo("."); } @@ -177,6 +184,7 @@ class BindConverterTests { BindConverter bindConverter = BindConverter.get(Collections.singletonList(new GenericConversionService()), null); Duration result = bindConverter.convert("10s", ResolvableType.forClass(Duration.class)); + assertThat(result).isNotNull(); assertThat(result.getSeconds()).isEqualTo(10); } @@ -215,7 +223,7 @@ class BindConverterTests { } private BindConverter getPropertyEditorOnlyBindConverter( - Consumer propertyEditorInitializer) { + @Nullable Consumer propertyEditorInitializer) { return BindConverter.get(Collections.singletonList(new ThrowingConversionService()), propertyEditorInitializer); } @@ -231,9 +239,9 @@ class BindConverterTests { static class SampleType { - private String text; + private @Nullable String text; - String getText() { + @Nullable String getText() { return this.text; } @@ -266,9 +274,9 @@ class BindConverterTests { static class ConventionType { - private String text; + private @Nullable String text; - String getText() { + @Nullable String getText() { return this.text; } @@ -291,22 +299,22 @@ class BindConverterTests { static class ThrowingConversionService implements ConversionService { @Override - public boolean canConvert(Class sourceType, Class targetType) { + public boolean canConvert(@Nullable Class sourceType, Class targetType) { throw new AssertionError("Should not call conversion service"); } @Override - public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { + public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { throw new AssertionError("Should not call conversion service"); } @Override - public T convert(Object source, Class targetType) { + public T convert(@Nullable Object source, Class targetType) { throw new AssertionError("Should not call conversion service"); } @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { throw new AssertionError("Should not call conversion service"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindResultTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindResultTests.java index cd9f6931b78..c992695801d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindResultTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindResultTests.java @@ -44,12 +44,15 @@ import static org.mockito.BDDMockito.then; class BindResultTests { @Mock + @SuppressWarnings("NullAway.Init") private Consumer consumer; @Mock + @SuppressWarnings("NullAway.Init") private Function mapper; @Mock + @SuppressWarnings("NullAway.Init") private Supplier supplier; @Test @@ -78,6 +81,7 @@ class BindResultTests { } @Test + @SuppressWarnings("NullAway") // Test null check void ifBoundWhenConsumerIsNullShouldThrowException() { BindResult result = BindResult.of("foo"); assertThatIllegalArgumentException().isThrownBy(() -> result.ifBound(null)) @@ -99,6 +103,7 @@ class BindResultTests { } @Test + @SuppressWarnings("NullAway") // Test null check void mapWhenMapperIsNullShouldThrowException() { BindResult result = BindResult.of("foo"); assertThatIllegalArgumentException().isThrownBy(() -> result.map(null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java index 7e0f88b52d7..b4f08e64b60 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.function.Consumer; import org.apache.tomcat.jdbc.pool.PoolProperties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.ExecutableHint; @@ -295,7 +296,7 @@ class BindableRuntimeHintsRegistrarTests { throws NoSuchMethodException, SecurityException { Constructor constructor = PoolProperties.InterceptorProperty.class.getConstructor(String.class, String.class); - String[] parameterNames = new StandardReflectionParameterNameDiscoverer().getParameterNames(constructor); + @Nullable String[] parameterNames = new StandardReflectionParameterNameDiscoverer().getParameterNames(constructor); assertThat(parameterNames).isNull(); assertThatNoException().isThrownBy(() -> registerHints(PoolProperties.class)); } @@ -425,24 +426,24 @@ class BindableRuntimeHintsRegistrarTests { public static class WithExternalNested { - private String name; + private @Nullable String name; @NestedConfigurationProperty - private SampleType sampleType; + private @Nullable SampleType sampleType; - public String getName() { + public @Nullable String getName() { return this.name; } - public void setName(String name) { + public void setName(@Nullable String name) { this.name = name; } - public SampleType getSampleType() { + public @Nullable SampleType getSampleType() { return this.sampleType; } - public void setSampleType(SampleType sampleType) { + public void setSampleType(@Nullable SampleType sampleType) { this.sampleType = sampleType; } @@ -451,13 +452,13 @@ class BindableRuntimeHintsRegistrarTests { public static class WithRecursive { @NestedConfigurationProperty - private Recursive recursive; + private @Nullable Recursive recursive; - public Recursive getRecursive() { + public @Nullable Recursive getRecursive() { return this.recursive; } - public void setRecursive(Recursive recursive) { + public void setRecursive(@Nullable Recursive recursive) { this.recursive = recursive; } @@ -466,9 +467,9 @@ class BindableRuntimeHintsRegistrarTests { public static class ImmutableWithRecursive { @NestedConfigurationProperty - private final ImmutableRecursive recursive; + private final @Nullable ImmutableRecursive recursive; - ImmutableWithRecursive(ImmutableRecursive recursive) { + ImmutableWithRecursive(@Nullable ImmutableRecursive recursive) { this.recursive = recursive; } @@ -476,8 +477,10 @@ class BindableRuntimeHintsRegistrarTests { public static class WithWellKnownTypes implements ApplicationContextAware, EnvironmentAware { + @SuppressWarnings("NullAway.Init") private ApplicationContext applicationContext; + @SuppressWarnings("NullAway.Init") private Environment environment; public ApplicationContext getApplicationContext() { @@ -516,23 +519,23 @@ class BindableRuntimeHintsRegistrarTests { public static class PackagePrivateGettersAndSetters { - private String alpha; + private @Nullable String alpha; - private Map bravo; + private @Nullable Map bravo; - String getAlpha() { + @Nullable String getAlpha() { return this.alpha; } - void setAlpha(String alpha) { + void setAlpha(@Nullable String alpha) { this.alpha = alpha; } - Map getBravo() { + @Nullable Map getBravo() { return this.bravo; } - void setBravo(Map bravo) { + void setBravo(@Nullable Map bravo) { this.bravo = bravo; } @@ -563,13 +566,13 @@ class BindableRuntimeHintsRegistrarTests { public static class Recursive { - private Recursive recursive; + private @Nullable Recursive recursive; - public Recursive getRecursive() { + public @Nullable Recursive getRecursive() { return this.recursive; } - public void setRecursive(Recursive recursive) { + public void setRecursive(@Nullable Recursive recursive) { this.recursive = recursive; } @@ -578,9 +581,9 @@ class BindableRuntimeHintsRegistrarTests { public static class ImmutableRecursive { @SuppressWarnings("unused") - private final ImmutableRecursive recursive; + private final @Nullable ImmutableRecursive recursive; - ImmutableRecursive(ImmutableRecursive recursive) { + ImmutableRecursive(@Nullable ImmutableRecursive recursive) { this.recursive = recursive; } @@ -589,13 +592,13 @@ class BindableRuntimeHintsRegistrarTests { public static class WithCrossReference { @NestedConfigurationProperty - private CrossReferenceA crossReferenceA; + private @Nullable CrossReferenceA crossReferenceA; - public void setCrossReferenceA(CrossReferenceA crossReferenceA) { + public void setCrossReferenceA(@Nullable CrossReferenceA crossReferenceA) { this.crossReferenceA = crossReferenceA; } - public CrossReferenceA getCrossReferenceA() { + public @Nullable CrossReferenceA getCrossReferenceA() { return this.crossReferenceA; } @@ -604,13 +607,13 @@ class BindableRuntimeHintsRegistrarTests { public static class CrossReferenceA { @NestedConfigurationProperty - private CrossReferenceB crossReferenceB; + private @Nullable CrossReferenceB crossReferenceB; - public void setCrossReferenceB(CrossReferenceB crossReferenceB) { + public void setCrossReferenceB(@Nullable CrossReferenceB crossReferenceB) { this.crossReferenceB = crossReferenceB; } - public CrossReferenceB getCrossReferenceB() { + public @Nullable CrossReferenceB getCrossReferenceB() { return this.crossReferenceB; } @@ -618,13 +621,13 @@ class BindableRuntimeHintsRegistrarTests { public static class CrossReferenceB { - private CrossReferenceA crossReferenceA; + private @Nullable CrossReferenceA crossReferenceA; - public void setCrossReferenceA(CrossReferenceA crossReferenceA) { + public void setCrossReferenceA(@Nullable CrossReferenceA crossReferenceA) { this.crossReferenceA = crossReferenceA; } - public CrossReferenceA getCrossReferenceA() { + public @Nullable CrossReferenceA getCrossReferenceA() { return this.crossReferenceA; } @@ -633,9 +636,9 @@ class BindableRuntimeHintsRegistrarTests { public static class WithGeneric { @NestedConfigurationProperty - private GenericObject generic; + private @Nullable GenericObject generic; - public GenericObject getGeneric() { + public @Nullable GenericObject getGeneric() { return this.generic; } @@ -665,13 +668,13 @@ class BindableRuntimeHintsRegistrarTests { public static class Nested { - private String field; + private @Nullable String field; - public String getField() { + public @Nullable String getField() { return this.field; } - public void setField(String field) { + public void setField(@Nullable String field) { this.field = field; } @@ -697,13 +700,13 @@ class BindableRuntimeHintsRegistrarTests { public static class Nested { - private String field; + private @Nullable String field; - public String getField() { + public @Nullable String getField() { return this.field; } - public void setField(String field) { + public void setField(@Nullable String field) { this.field = field; } @@ -715,25 +718,25 @@ class BindableRuntimeHintsRegistrarTests { public abstract static class BaseProperties { - private InheritedNested inheritedNested; + private @Nullable InheritedNested inheritedNested; - public InheritedNested getInheritedNested() { + public @Nullable InheritedNested getInheritedNested() { return this.inheritedNested; } - public void setInheritedNested(InheritedNested inheritedNested) { + public void setInheritedNested(@Nullable InheritedNested inheritedNested) { this.inheritedNested = inheritedNested; } public static class InheritedNested { - private String alpha; + private @Nullable String alpha; - public String getAlpha() { + public @Nullable String getAlpha() { return this.alpha; } - public void setAlpha(String alpha) { + public void setAlpha(@Nullable String alpha) { this.alpha = alpha; } @@ -743,13 +746,13 @@ class BindableRuntimeHintsRegistrarTests { public static class ExtendingProperties extends BaseProperties { - private String bravo; + private @Nullable String bravo; - public String getBravo() { + public @Nullable String getBravo() { return this.bravo; } - public void setBravo(String bravo) { + public void setBravo(@Nullable String bravo) { this.bravo = bravo; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableTests.java index 6fe74ef1f58..38ffea039bc 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; @@ -41,12 +42,14 @@ import static org.mockito.Mockito.mock; class BindableTests { @Test + @SuppressWarnings("NullAway") // Test null check void ofClassWhenTypeIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> Bindable.of((Class) null)) .withMessageContaining("'type' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void ofTypeWhenTypeIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> Bindable.of((ResolvableType) null)) .withMessageContaining("'type' must not be null"); @@ -68,18 +71,23 @@ class BindableTests { String instance = "foo"; ResolvableType type = ResolvableType.forClass(String.class); assertThat(Bindable.ofInstance(instance).getType()).isEqualTo(type); - assertThat(Bindable.ofInstance(instance).getValue().get()).isEqualTo("foo"); + Supplier value = Bindable.ofInstance(instance).getValue(); + assertThat(value).isNotNull(); + assertThat(value.get()).isEqualTo("foo"); } @Test void ofClassWithExistingValueShouldSetTypeAndExistingValue() { - assertThat(Bindable.of(String.class).withExistingValue("foo").getValue().get()).isEqualTo("foo"); + Supplier value = Bindable.of(String.class).withExistingValue("foo").getValue(); + assertThat(value).isNotNull(); + assertThat(value.get()).isEqualTo("foo"); } @Test void ofTypeWithExistingValueShouldSetTypeAndExistingValue() { - assertThat(Bindable.of(ResolvableType.forClass(String.class)).withExistingValue("foo").getValue().get()) - .isEqualTo("foo"); + Supplier value = Bindable.of(ResolvableType.forClass(String.class)).withExistingValue("foo").getValue(); + assertThat(value).isNotNull(); + assertThat(value.get()).isEqualTo("foo"); } @Test @@ -93,7 +101,9 @@ class BindableTests { void ofTypeWhenPrimitiveWithExistingValueWrapperShouldNotThrowException() { Bindable bindable = Bindable.of(ResolvableType.forClass(int.class)).withExistingValue(123); assertThat(bindable.getType().resolve()).isEqualTo(int.class); - assertThat(bindable.getValue().get()).isEqualTo(123); + Supplier value = bindable.getValue(); + assertThat(value).isNotNull(); + assertThat(value.get()).isEqualTo(123); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java index f11bbd0c795..6ba4b3f190e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import jakarta.validation.Validation; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mockito.InOrder; import org.mockito.invocation.InvocationOnMock; @@ -71,12 +72,14 @@ class BinderTests { private Binder binder = new Binder(this.sources); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenSourcesIsNullArrayShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new Binder((ConfigurationPropertySource[]) null)) .withMessageContaining("'sources' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenSourcesIsNullIterableShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new Binder((Iterable) null)) .withMessageContaining("'sources' must not be null"); @@ -95,6 +98,7 @@ class BinderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void bindWhenNameIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.binder.bind((ConfigurationPropertyName) null, Bindable.of(String.class), @@ -103,6 +107,7 @@ class BinderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void bindWhenTargetIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.binder.bind(ConfigurationPropertyName.of("foo"), null, BindHandler.DEFAULT)) @@ -268,7 +273,7 @@ class BinderTests { ConfigurationPropertySources.from(new PropertySource("test") { @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return null; } @@ -301,7 +306,7 @@ class BinderTests { Map source = new HashMap<>(); source.put("value", "hello"); source.put("", "bar"); - Iterable propertySources = ConfigurationPropertySources + Iterable<@Nullable ConfigurationPropertySource> propertySources = ConfigurationPropertySources .from(new MapPropertySource("test", source)); propertySources.forEach(this.sources::add); Bindable target = Bindable.of(JavaBean.class); @@ -330,7 +335,8 @@ class BinderTests { BindResult result = this.binder.bind("foo", Bindable.of(JavaBean.class), new BindHandler() { @Override - public Bindable onStart(ConfigurationPropertyName name, Bindable target, BindContext context) { + public @Nullable Bindable onStart(ConfigurationPropertyName name, Bindable target, + BindContext context) { return null; } @@ -372,15 +378,15 @@ class BinderTests { static class JavaBean { - private String value; + private @Nullable String value; private final List items = Collections.emptyList(); - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } @@ -433,13 +439,13 @@ class BinderTests { @Validated static class ResourceBean { - private Resource resource; + private @Nullable Resource resource; - Resource getResource() { + @Nullable Resource getResource() { return this.resource; } - void setResource(Resource resource) { + void setResource(@Nullable Resource resource) { this.resource = resource; } @@ -447,13 +453,13 @@ class BinderTests { static class CycleBean1 { - private CycleBean2 two; + private @Nullable CycleBean2 two; - CycleBean2 getTwo() { + @Nullable CycleBean2 getTwo() { return this.two; } - void setTwo(CycleBean2 two) { + void setTwo(@Nullable CycleBean2 two) { this.two = two; } @@ -461,13 +467,13 @@ class BinderTests { static class CycleBean2 { - private CycleBean1 one; + private @Nullable CycleBean1 one; - CycleBean1 getOne() { + @Nullable CycleBean1 getOne() { return this.one; } - void setOne(CycleBean1 one) { + void setOne(@Nullable CycleBean1 one) { this.one = one; } @@ -475,13 +481,13 @@ class BinderTests { static class GenericBean { - private T bar; + private @Nullable T bar; - T getBar() { + @Nullable T getBar() { return this.bar; } - void setBar(T bar) { + void setBar(@Nullable T bar) { this.bar = bar; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandlerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandlerTests.java index 5d3fe12dcc1..6a41e94550e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandlerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandlerTests.java @@ -49,6 +49,7 @@ class BoundPropertiesTrackingBindHandlerTests { private Binder binder; @Mock + @SuppressWarnings("NullAway.Init") private Consumer consumer; @BeforeEach diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java index 0638d6f0035..f5e84818964 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.bind.BinderTests.ExampleEnum; @@ -117,7 +118,9 @@ class CollectionBinderTests { this.sources.add(source); assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind("foo", INTEGER_LIST)) .satisfies((ex) -> { - Set unbound = ((UnboundConfigurationPropertiesException) ex.getCause()) + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + Set unbound = ((UnboundConfigurationPropertiesException) cause) .getUnboundProperties(); assertThat(unbound).singleElement().satisfies((property) -> { assertThat(property.getName()).hasToString("foo[3]"); @@ -137,7 +140,9 @@ class CollectionBinderTests { assertThatExceptionOfType(BindException.class) .isThrownBy(() -> this.binder.bind("foo", Bindable.listOf(Name.class))) .satisfies((ex) -> { - Set unbound = ((UnboundConfigurationPropertiesException) ex.getCause()) + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + Set unbound = ((UnboundConfigurationPropertiesException) cause) .getUnboundProperties(); assertThat(unbound).singleElement().satisfies((property) -> { assertThat(property.getName()).hasToString("foo[1].missing"); @@ -171,7 +176,9 @@ class CollectionBinderTests { Bindable> target = Bindable.listOf(JavaBean.class); assertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind("foo", target)) .satisfies((ex) -> { - Set unbound = ((UnboundConfigurationPropertiesException) ex.getCause()) + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + Set unbound = ((UnboundConfigurationPropertiesException) cause) .getUnboundProperties(); assertThat(unbound).singleElement().satisfies((property) -> { assertThat(property.getName()).hasToString("foo[4].value"); @@ -394,8 +401,10 @@ class CollectionBinderTests { Bindable target = Bindable.of(BeanWithNestedCollection.class); BeanWithNestedCollection foo = this.binder.bind("foo", target).get(); assertThat(foo.getValue()).isEqualTo("one"); - assertThat(foo.getFoos().get(0).getValue()).isEqualTo("two"); - assertThat(foo.getFoos().get(1).getValue()).isEqualTo("three"); + List foos = foo.getFoos(); + assertThat(foos).isNotNull(); + assertThat(foos.get(0).getValue()).isEqualTo("two"); + assertThat(foos.get(1).getValue()).isEqualTo("three"); } @Test @@ -465,7 +474,9 @@ class CollectionBinderTests { source.put("foo.values[0]", "foo-bar,bar-baz"); this.sources.add(source); BeanWithEnumSetCollection result = this.binder.bind("foo", Bindable.of(BeanWithEnumSetCollection.class)).get(); - assertThat(result.getValues().get(0)).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ); + List> values = result.getValues(); + assertThat(values).isNotNull(); + assertThat(values.get(0)).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ); } @Test @@ -504,7 +515,7 @@ class CollectionBinderTests { private Set itemsSet = new LinkedHashSet<>(); - private String string; + private @Nullable String string; List getItems() { return this.items; @@ -522,11 +533,11 @@ class CollectionBinderTests { this.itemsSet = itemsSet; } - String getString() { + @Nullable String getString() { return this.string; } - void setString(String string) { + void setString(@Nullable String string) { this.string = string; } @@ -576,23 +587,23 @@ class CollectionBinderTests { static class BeanWithNestedCollection { - private String value; + private @Nullable String value; - private List foos; + private @Nullable List foos; - List getFoos() { + @Nullable List getFoos() { return this.foos; } - void setFoos(List foos) { + void setFoos(@Nullable List foos) { this.foos = foos; } - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } @@ -600,13 +611,13 @@ class CollectionBinderTests { static class ClonedArrayBean { - private String[] bar; + private String @Nullable [] bar; - String[] getBar() { - return this.bar.clone(); + String @Nullable [] getBar() { + return (this.bar != null) ? this.bar.clone() : null; } - void setBar(String[] bar) { + void setBar(String @Nullable [] bar) { this.bar = bar; } @@ -614,13 +625,13 @@ class CollectionBinderTests { static class BeanWithGetterException { - private List values; + private @Nullable List values; - void setValues(List values) { + void setValues(@Nullable List values) { this.values = values; } - List getValues() { + @Nullable List getValues() { return Collections.unmodifiableList(this.values); } @@ -628,13 +639,13 @@ class CollectionBinderTests { static class BeanWithEnumSetCollection { - private List> values; + private @Nullable List> values; - void setValues(List> values) { + void setValues(@Nullable List> values) { this.values = values; } - List> getValues() { + @Nullable List> getValues() { return this.values; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java index 7beea81781d..eece843ebd7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.bind.JavaBeanBinder.Bean; @@ -271,8 +272,10 @@ class JavaBeanBinderTests { source.put("foo.value-bean.string-value", "foo"); this.sources.add(source); ExampleNestedBean bean = this.binder.bind("foo", Bindable.of(ExampleNestedBean.class)).get(); - assertThat(bean.getValueBean().getIntValue()).isEqualTo(123); - assertThat(bean.getValueBean().getStringValue()).isEqualTo("foo"); + ExampleValueBean valueBean = bean.getValueBean(); + assertThat(valueBean).isNotNull(); + assertThat(valueBean.getIntValue()).isEqualTo(123); + assertThat(valueBean.getStringValue()).isEqualTo("foo"); } @Test @@ -505,8 +508,12 @@ class JavaBeanBinderTests { source.put("foo.booleans[b].value", "true"); this.sources.add(source); ExampleWithGenericMap bean = this.binder.bind("foo", Bindable.of(ExampleWithGenericMap.class)).get(); - assertThat(bean.getIntegers().get("a").getValue()).isOne(); - assertThat(bean.getBooleans().get("b").getValue()).isTrue(); + GenericValue a = bean.getIntegers().get("a"); + assertThat(a).isNotNull(); + assertThat(a.getValue()).isOne(); + GenericValue b = bean.getBooleans().get("b"); + assertThat(b).isNotNull(); + assertThat(b.getValue()).isTrue(); } @Test @@ -524,7 +531,9 @@ class JavaBeanBinderTests { void beanPropertiesPreferMatchingType() { // gh-16206 ResolvableType type = ResolvableType.forClass(PropertyWithOverloadedSetter.class); - Bean bean = new Bean<>(type, type.resolve()) { + Class resolvedType = type.resolve(); + assertThat(resolvedType).isNotNull(); + Bean bean = new Bean<>(type, resolvedType) { @Override protected void addProperties(Method[] declaredMethods, Field[] declaredFields) { @@ -553,6 +562,7 @@ class JavaBeanBinderTests { }; BeanProperty property = bean.getProperties().get("property"); + assertThat(property).isNotNull(); PropertyWithOverloadedSetter target = new PropertyWithOverloadedSetter(); property.setValue(() -> target, "some string"); } @@ -621,9 +631,9 @@ class JavaBeanBinderTests { private long longValue; - private String stringValue; + private @Nullable String stringValue; - private ExampleEnum enumValue; + private @Nullable ExampleEnum enumValue; int getIntValue() { return this.intValue; @@ -641,19 +651,19 @@ class JavaBeanBinderTests { this.longValue = longValue; } - String getStringValue() { + @Nullable String getStringValue() { return this.stringValue; } - void setStringValue(String stringValue) { + void setStringValue(@Nullable String stringValue) { this.stringValue = stringValue; } - ExampleEnum getEnumValue() { + @Nullable ExampleEnum getEnumValue() { return this.enumValue; } - void setEnumValue(ExampleEnum enumValue) { + void setEnumValue(@Nullable ExampleEnum enumValue) { this.enumValue = enumValue; } @@ -662,13 +672,13 @@ class JavaBeanBinderTests { static class ExampleRenamedPropertyBean { @Name("public") - private String exampleProperty; + private @Nullable String exampleProperty; - String getExampleProperty() { + @Nullable String getExampleProperty() { return this.exampleProperty; } - void setExampleProperty(String exampleProperty) { + void setExampleProperty(@Nullable String exampleProperty) { this.exampleProperty = exampleProperty; } @@ -700,13 +710,13 @@ class JavaBeanBinderTests { static class ExampleMapBean { - private Map map; + private @Nullable Map map; - Map getMap() { + @Nullable Map getMap() { return this.map; } - void setMap(Map map) { + void setMap(@Nullable Map map) { this.map = map; } @@ -714,13 +724,13 @@ class JavaBeanBinderTests { static class ExampleListBean { - private List list; + private @Nullable List list; - List getList() { + @Nullable List getList() { return this.list; } - void setList(List list) { + void setList(@Nullable List list) { this.list = list; } @@ -728,13 +738,13 @@ class JavaBeanBinderTests { static class ExampleSetBean { - private Set set; + private @Nullable Set set; - Set getSet() { + @Nullable Set getSet() { return this.set; } - void setSet(Set set) { + void setSet(@Nullable Set set) { this.set = set; } @@ -742,13 +752,13 @@ class JavaBeanBinderTests { static class ExampleCollectionBean { - private Collection collection; + private @Nullable Collection collection; - Collection getCollection() { + @Nullable Collection getCollection() { return this.collection; } - void setCollection(Collection collection) { + void setCollection(@Nullable Collection collection) { this.collection = collection; } @@ -797,13 +807,13 @@ class JavaBeanBinderTests { static class ExampleCollectionBeanWithDelimiter { @Delimiter("|") - private Collection collection; + private @Nullable Collection collection; - Collection getCollection() { + @Nullable Collection getCollection() { return this.collection; } - void setCollection(Collection collection) { + void setCollection(@Nullable Collection collection) { this.collection = collection; } @@ -811,13 +821,13 @@ class JavaBeanBinderTests { static class ExampleNestedBean { - private ExampleValueBean valueBean; + private @Nullable ExampleValueBean valueBean; - ExampleValueBean getValueBean() { + @Nullable ExampleValueBean getValueBean() { return this.valueBean; } - void setValueBean(ExampleValueBean valueBean) { + void setValueBean(@Nullable ExampleValueBean valueBean) { this.valueBean = valueBean; } @@ -863,14 +873,14 @@ class JavaBeanBinderTests { static class ExampleNestedSubclassBean extends ExampleNestedBean { - private ExampleValueSubclassBean valueBean; + private @Nullable ExampleValueSubclassBean valueBean; @Override - ExampleValueSubclassBean getValueBean() { + @Nullable ExampleValueSubclassBean getValueBean() { return this.valueBean; } - void setValueBean(ExampleValueSubclassBean valueBean) { + void setValueBean(@Nullable ExampleValueSubclassBean valueBean) { this.valueBean = valueBean; } @@ -892,17 +902,17 @@ class JavaBeanBinderTests { static class ExampleWithNonDefaultConstructor { - private String value; + private @Nullable String value; - ExampleWithNonDefaultConstructor(String value) { + ExampleWithNonDefaultConstructor(@Nullable String value) { this.value = value; } - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } @@ -976,7 +986,7 @@ class JavaBeanBinderTests { private int value; - private ExampleWithSelfReference self; + private @Nullable ExampleWithSelfReference self; int getValue() { return this.value; @@ -986,11 +996,11 @@ class JavaBeanBinderTests { this.value = value; } - ExampleWithSelfReference getSelf() { + @Nullable ExampleWithSelfReference getSelf() { return this.self; } - void setSelf(ExampleWithSelfReference self) { + void setSelf(@Nullable ExampleWithSelfReference self) { this.self = self; } @@ -998,13 +1008,13 @@ class JavaBeanBinderTests { static class ExampleWithInvalidAccessors { - private String name; + private @Nullable String name; - String getName() { + @Nullable String getName() { return this.name; } - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } @@ -1020,15 +1030,15 @@ class JavaBeanBinderTests { static class ExampleWithStaticAccessors { - private static String name; + private static @Nullable String name; private int counter; - static String getName() { + static @Nullable String getName() { return name; } - static void setName(String name) { + static void setName(@Nullable String name) { ExampleWithStaticAccessors.name = name; } @@ -1053,13 +1063,13 @@ class JavaBeanBinderTests { static class ConverterAnnotatedExampleBean { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) - private LocalDate date; + private @Nullable LocalDate date; - LocalDate getDate() { + @Nullable LocalDate getDate() { return this.date; } - void setDate(LocalDate date) { + void setDate(@Nullable LocalDate date) { this.date = date; } @@ -1067,13 +1077,13 @@ class JavaBeanBinderTests { static class ExampleWithPropertyEditorType { - private Class value; + private @Nullable Class value; - Class getValue() { + @Nullable Class getValue() { return this.value; } - void setValue(Class value) { + void setValue(@Nullable Class value) { this.value = value; } @@ -1097,13 +1107,13 @@ class JavaBeanBinderTests { static class GenericValue { - private T value; + private @Nullable T value; - T getValue() { + @Nullable T getValue() { return this.value; } - void setValue(T value) { + void setValue(@Nullable T value) { this.value = value; } @@ -1111,17 +1121,17 @@ class JavaBeanBinderTests { static class PropertyWithOverloadedSetter { - private String property; + private @Nullable String property; void setProperty(int property) { this.property = String.valueOf(property); } - void setProperty(String property) { + void setProperty(@Nullable String property) { this.property = property; } - String getProperty() { + @Nullable String getProperty() { return this.property; } @@ -1143,13 +1153,13 @@ class JavaBeanBinderTests { static class PackagePrivateSetterBean { - private String property; + private @Nullable String property; - String getProperty() { + @Nullable String getProperty() { return this.property; } - void setProperty(String property) { + void setProperty(@Nullable String property) { this.property = property; } @@ -1225,13 +1235,13 @@ class JavaBeanBinderTests { static class BridgeMethodsBase { - private T value; + private @Nullable T value; - T getValue() { + @Nullable T getValue() { return this.value; } - void setValue(T value) { + void setValue(@Nullable T value) { this.value = value; } @@ -1240,7 +1250,7 @@ class JavaBeanBinderTests { static class BridgeMethods extends BridgeMethodsBase { @Override - BridgeType getValue() { + @Nullable BridgeType getValue() { return super.getValue(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanWithPublicConstructor.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanWithPublicConstructor.java index 20f9efc55eb..8ef57bc44b1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanWithPublicConstructor.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanWithPublicConstructor.java @@ -16,6 +16,8 @@ package org.springframework.boot.context.properties.bind; +import org.jspecify.annotations.Nullable; + /** * Java bean with an additional public single-arg constructor. * @@ -23,7 +25,7 @@ package org.springframework.boot.context.properties.bind; */ public class JavaBeanWithPublicConstructor { - private String value; + private @Nullable String value; public JavaBeanWithPublicConstructor() { } @@ -32,11 +34,11 @@ public class JavaBeanWithPublicConstructor { setValue(value); } - public String getValue() { + public @Nullable String getValue() { return this.value; } - public void setValue(String value) { + public void setValue(@Nullable String value) { this.value = value; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java index ed39513d046..7b591d785a1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java @@ -29,6 +29,7 @@ import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.mockito.InOrder; import org.mockito.invocation.InvocationOnMock; @@ -369,7 +370,9 @@ class MapBinderTests { source.put("foo.bar[2].value", "c"); this.sources.add(source); Map> map = this.binder.bind("foo", target).get(); - List values = map.get("bar").stream().map(JavaBean::getValue).toList(); + List bar = map.get("bar"); + assertThat(bar).isNotNull(); + List values = bar.stream().map(JavaBean::getValue).toList(); assertThat(values).containsExactly("a", "b", "c"); } @@ -387,7 +390,9 @@ class MapBinderTests { this.sources.add(new MockConfigurationPropertySource("foo.bar.pattern", "1", "line1")); Bindable> target = Bindable.mapOf(String.class, Foo.class); Map map = this.binder.bind("foo", target).get(); - assertThat(map.get("bar").getPattern()).isEqualTo("1"); + Foo bar = map.get("bar"); + assertThat(bar).isNotNull(); + assertThat(bar.getPattern()).isEqualTo("1"); } @Test @@ -434,7 +439,9 @@ class MapBinderTests { mockSource.put("foo.bar.baz[2].value", "c"); this.sources.add(mockSource); Map> map = this.binder.bind("foo", target).get(); - List values = map.get("bar.baz").stream().map(JavaBean::getValue).toList(); + List barBaz = map.get("bar.baz"); + assertThat(barBaz).isNotNull(); + List values = barBaz.stream().map(JavaBean::getValue).toList(); assertThat(values).containsExactly("a", "b", "c"); } @@ -495,8 +502,12 @@ class MapBinderTests { this.sources.add(source); BindResult foo = this.binder.bind("foo", NestableFoo.class); assertThat(foo.get().getValue()).isNotNull(); - assertThat(foo.get().getFoos().get("foo1").getValue()).isEqualTo("two"); - assertThat(foo.get().getFoos().get("foo2").getValue()).isEqualTo("three"); + NestableFoo foo1 = foo.get().getFoos().get("foo1"); + assertThat(foo1).isNotNull(); + assertThat(foo1.getValue()).isEqualTo("two"); + NestableFoo foo2 = foo.get().getFoos().get("foo2"); + assertThat(foo2).isNotNull(); + assertThat(foo2.getValue()).isEqualTo("three"); } @Test @@ -611,8 +622,11 @@ class MapBinderTests { source.put("foo.addresses.localhost[1]", "127.0.0.2"); this.sources.add(source); MapWithWildcardProperties result = this.binder.bind("foo", Bindable.of(MapWithWildcardProperties.class)).get(); - assertThat(result.getAddresses().get("localhost").stream().map(InetAddress::getHostAddress)) - .containsExactly("127.0.0.1", "127.0.0.2"); + Map> addresses = result.getAddresses(); + assertThat(addresses).isNotNull(); + List localhost = addresses.get("localhost"); + assertThat(localhost).isNotNull(); + assertThat(localhost.stream().map(InetAddress::getHostAddress)).containsExactly("127.0.0.1", "127.0.0.2"); } @Test @@ -670,20 +684,20 @@ class MapBinderTests { static class Foo { - private String pattern; + private @Nullable String pattern; Foo() { } - Foo(String pattern) { + Foo(@Nullable String pattern) { this.pattern = pattern; } - String getPattern() { + @Nullable String getPattern() { return this.pattern; } - void setPattern(String pattern) { + void setPattern(@Nullable String pattern) { this.pattern = pattern; } @@ -693,17 +707,17 @@ class MapBinderTests { private final Map foos = new LinkedHashMap<>(); - private String value; + private @Nullable String value; Map getFoos() { return this.foos; } - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } @@ -762,13 +776,13 @@ class MapBinderTests { static class BeanWithGetterException { - private Map values; + private @Nullable Map values; - void setValues(Map values) { + void setValues(@Nullable Map values) { this.values = values; } - Map getValues() { + @Nullable Map getValues() { return Collections.unmodifiableMap(this.values); } @@ -776,13 +790,13 @@ class MapBinderTests { static class MapWithWildcardProperties { - private Map> addresses; + private @Nullable Map> addresses; - Map> getAddresses() { + @Nullable Map> getAddresses() { return this.addresses; } - void setAddresses(Map> addresses) { + void setAddresses(@Nullable Map> addresses) { this.addresses = addresses; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolverTests.java index f781a57f101..e2d5bb2e3a8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolverTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.core.env.Environment; @@ -38,9 +39,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException */ class PropertySourcesPlaceholdersResolverTests { - private PropertySourcesPlaceholdersResolver resolver; + private @Nullable PropertySourcesPlaceholdersResolver resolver; @Test + @SuppressWarnings("NullAway") // Test null check void placeholderResolverIfEnvironmentNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new PropertySourcesPlaceholdersResolver((Environment) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java index d286989993c..2f1d0bd3b4b 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java @@ -28,6 +28,7 @@ import java.util.Optional; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.internal.CharacterIndex; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.source.ConfigurationPropertyName; @@ -733,9 +734,9 @@ class ValueObjectBinderTests { static class NestedJavaBean { - private String value; + private @Nullable String value; - String getValue() { + @Nullable String getValue() { return this.value; } @@ -903,23 +904,23 @@ class ValueObjectBinderTests { static class NonExtractableParameterName { - private String value; + private @Nullable String value; - private JsonPath jsonPath; + private @Nullable JsonPath jsonPath; - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } - JsonPath getJsonPath() { + @Nullable JsonPath getJsonPath() { return this.jsonPath; } - void setJsonPath(JsonPath jsonPath) { + void setJsonPath(@Nullable JsonPath jsonPath) { this.jsonPath = jsonPath; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandlerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandlerTests.java index febe513b77c..8b485f87997 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandlerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandlerTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -89,7 +90,7 @@ class IgnoreTopLevelConverterNotFoundBindHandlerTests { private int foo; - private Map map; + private @Nullable Map map; int getFoo() { return this.foo; @@ -99,11 +100,11 @@ class IgnoreTopLevelConverterNotFoundBindHandlerTests { throw new IllegalStateException(); } - Map getMap() { + @Nullable Map getMap() { return this.map; } - void setMap(Map map) { + void setMap(@Nullable Map map) { this.map = map; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandlerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandlerTests.java index 78bafc0cbe2..00031eab530 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandlerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandlerTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.bind.handler; import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.bind.BindException; @@ -42,7 +43,7 @@ class NoUnboundElementsBindHandlerTests { private final List sources = new ArrayList<>(); - private Binder binder; + private @Nullable Binder binder; @Test void bindWhenNotUsingNoUnboundElementsHandlerShouldBind() { @@ -73,11 +74,14 @@ class NoUnboundElementsBindHandlerTests { source.put("example.baz", "bar"); this.sources.add(source); this.binder = new Binder(this.sources); - assertThatExceptionOfType(BindException.class) - .isThrownBy( - () -> this.binder.bind("example", Bindable.of(Example.class), new NoUnboundElementsBindHandler())) - .satisfies((ex) -> assertThat(ex.getCause().getMessage()) - .contains("The elements [example.baz] were left unbound")); + assertThatExceptionOfType(BindException.class).isThrownBy(() -> { + assertThat(this.binder).isNotNull(); + this.binder.bind("example", Bindable.of(Example.class), new NoUnboundElementsBindHandler()); + }).satisfies((ex) -> { + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + assertThat(cause.getMessage()).contains("The elements [example.baz] were left unbound"); + }); } @Test @@ -126,11 +130,14 @@ class NoUnboundElementsBindHandlerTests { source.put("example.foo[0]", "bar"); this.sources.add(source); this.binder = new Binder(this.sources); - assertThatExceptionOfType(BindException.class) - .isThrownBy( - () -> this.binder.bind("example", Bindable.of(Example.class), new NoUnboundElementsBindHandler())) - .satisfies((ex) -> assertThat(ex.getCause().getMessage()) - .contains("The elements [example.foo[0]] were left unbound")); + assertThatExceptionOfType(BindException.class).isThrownBy(() -> { + assertThat(this.binder).isNotNull(); + this.binder.bind("example", Bindable.of(Example.class), new NoUnboundElementsBindHandler()); + }).satisfies((ex) -> { + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + assertThat(cause.getMessage()).contains("The elements [example.foo[0]] were left unbound"); + }); } @Test @@ -148,7 +155,9 @@ class NoUnboundElementsBindHandlerTests { NoUnboundElementsBindHandler handler = new NoUnboundElementsBindHandler(); ExampleWithNestedList bound = this.binder.bind("example", Bindable.of(ExampleWithNestedList.class), handler) .get(); - assertThat(bound.getNested().get(0).getStringValue()).isEqualTo("bar"); + List nested = bound.getNested(); + assertThat(nested).isNotNull(); + assertThat(nested.get(0).getStringValue()).isEqualTo("bar"); } @Test @@ -162,22 +171,25 @@ class NoUnboundElementsBindHandlerTests { this.sources.add(source1); this.sources.add(source2); this.binder = new Binder(this.sources); - assertThatExceptionOfType(BindException.class) - .isThrownBy(() -> this.binder.bind("example", Bindable.of(ExampleWithNestedList.class), - new NoUnboundElementsBindHandler())) - .satisfies((ex) -> assertThat(ex.getCause().getMessage()) - .contains("The elements [example.nested[1].invalid] were left unbound")); + assertThatExceptionOfType(BindException.class).isThrownBy(() -> { + assertThat(this.binder).isNotNull(); + this.binder.bind("example", Bindable.of(ExampleWithNestedList.class), new NoUnboundElementsBindHandler()); + }).satisfies((ex) -> { + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + assertThat(cause.getMessage()).contains("The elements [example.nested[1].invalid] were left unbound"); + }); } static class Example { - private String foo; + private @Nullable String foo; - String getFoo() { + @Nullable String getFoo() { return this.foo; } - void setFoo(String foo) { + void setFoo(@Nullable String foo) { this.foo = foo; } @@ -185,13 +197,13 @@ class NoUnboundElementsBindHandlerTests { static class ExampleWithList { - private List foo; + private @Nullable List foo; - List getFoo() { + @Nullable List getFoo() { return this.foo; } - void setFoo(List foo) { + void setFoo(@Nullable List foo) { this.foo = foo; } @@ -199,13 +211,13 @@ class NoUnboundElementsBindHandlerTests { static class ExampleWithNestedList { - private List nested; + private @Nullable List nested; - List getNested() { + @Nullable List getNested() { return this.nested; } - void setNested(List nested) { + void setNested(@Nullable List nested) { this.nested = nested; } @@ -213,33 +225,33 @@ class NoUnboundElementsBindHandlerTests { static class Nested { - private String stringValue; + private @Nullable String stringValue; - private Integer intValue; + private @Nullable Integer intValue; - private OtherNested otherNested; + private @Nullable OtherNested otherNested; - String getStringValue() { + @Nullable String getStringValue() { return this.stringValue; } - void setStringValue(String value) { + void setStringValue(@Nullable String value) { this.stringValue = value; } - Integer getIntValue() { + @Nullable Integer getIntValue() { return this.intValue; } - void setIntValue(Integer intValue) { + void setIntValue(@Nullable Integer intValue) { this.intValue = intValue; } - OtherNested getOtherNested() { + @Nullable OtherNested getOtherNested() { return this.otherNested; } - void setOtherNested(OtherNested otherNested) { + void setOtherNested(@Nullable OtherNested otherNested) { this.otherNested = otherNested; } @@ -247,13 +259,13 @@ class NoUnboundElementsBindHandlerTests { static class OtherNested { - private String baz; + private @Nullable String baz; - String getBaz() { + @Nullable String getBaz() { return this.baz; } - void setBaz(String baz) { + void setBaz(@Nullable String baz) { this.baz = baz; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/BindValidationExceptionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/BindValidationExceptionTests.java index b20910ed344..b33b6c89fe7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/BindValidationExceptionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/BindValidationExceptionTests.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.mock; class BindValidationExceptionTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenValidationErrorsIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new BindValidationException(null)) .withMessageContaining("'validationErrors' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java index 260b8fb7c54..c9ac953d553 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java @@ -25,6 +25,7 @@ import java.util.Set; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -268,7 +269,9 @@ class ValidationBindHandlerTests { action.run(); } catch (BindException ex) { - return (BindValidationException) ex.getCause(); + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + return (BindValidationException) cause; } throw new IllegalStateException("Did not throw"); } @@ -341,19 +344,20 @@ class ValidationBindHandlerTests { static class ExampleNested { - private String name; + private @Nullable String name; @Min(5) private int age; @NotNull + @SuppressWarnings("NullAway.Init") private String address; - String getName() { + @Nullable String getName() { return this.name; } - void setName(String name) { + void setName(@Nullable String name) { this.name = name; } @@ -423,13 +427,13 @@ class ValidationBindHandlerTests { static class ExampleMapValue { - private String number; + private @Nullable String number; - String getNumber() { + @Nullable String getNumber() { return this.number; } - void setNumber(String number) { + void setNumber(@Nullable String number) { this.number = number; } @@ -437,14 +441,14 @@ class ValidationBindHandlerTests { static class TestHandler extends AbstractBindHandler { - private final Object result; + private final @Nullable Object result; - TestHandler(Object result) { + TestHandler(@Nullable Object result) { this.result = result; } @Override - public Object onFailure(ConfigurationPropertyName name, Bindable target, BindContext context, + public @Nullable Object onFailure(ConfigurationPropertyName name, Bindable target, BindContext context, Exception error) throws Exception { return this.result; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationErrorsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationErrorsTests.java index 8e190ec2b29..ab0d16513d1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationErrorsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationErrorsTests.java @@ -45,6 +45,7 @@ class ValidationErrorsTests { private static final ConfigurationPropertyName NAME = ConfigurationPropertyName.of("foo"); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenNameIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new ValidationErrors(null, Collections.emptySet(), Collections.emptyList())) @@ -52,12 +53,14 @@ class ValidationErrorsTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenBoundPropertiesIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ValidationErrors(NAME, null, Collections.emptyList())) .withMessageContaining("'boundProperties' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenErrorsIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ValidationErrors(NAME, Collections.emptySet(), null)) .withMessageContaining("'errors' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySourceTests.java index 1a92ed1cc96..f86ff698f29 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySourceTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.properties.source; import java.util.Collections; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -98,7 +99,7 @@ class AliasedConfigurationPropertySourceTests { .isEqualTo(ConfigurationPropertyState.PRESENT); } - private Object getValue(ConfigurationPropertySource source, String name) { + private @Nullable Object getValue(ConfigurationPropertySource source, String name) { ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); return (property != null) ? property.getValue() : null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCachingTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCachingTests.java index 973d632c784..1a789db6225 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCachingTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCachingTests.java @@ -61,6 +61,7 @@ class ConfigurationPropertyCachingTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getFromSourcesWhenSourcesIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> ConfigurationPropertyCaching.get((Iterable) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliasesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliasesTests.java index 37a8a4535bd..3879f3ff54a 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliasesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliasesTests.java @@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ConfigurationPropertyNameAliasesTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWithStringWhenNullNameShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationPropertyNameAliases((String) null)) .withMessageContaining("'name' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java index 75e6c219884..4797e335025 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java @@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ConfigurationPropertyNameTests { @Test + @SuppressWarnings("NullAway") // Test null check void ofNameShouldNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyName.of(null)) .withMessageContaining("'name' must not be null"); @@ -231,6 +232,7 @@ class ConfigurationPropertyNameTests { } @Test + @SuppressWarnings("NullAway") // Test null check void adaptWhenNameIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyName.adapt(null, '.')) .withMessageContaining("Name must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourceTests.java index 3b0a093d12d..b4a3bcc6fef 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourceTests.java @@ -35,8 +35,10 @@ class ConfigurationPropertySourceTests { MockPropertySource source = new MockPropertySource(); source.setProperty("spring", "boot"); ConfigurationPropertySource adapted = ConfigurationPropertySource.from(source); - assertThat(adapted.getConfigurationProperty(ConfigurationPropertyName.of("spring")).getValue()) - .isEqualTo("boot"); + assertThat(adapted).isNotNull(); + ConfigurationProperty spring = adapted.getConfigurationProperty(ConfigurationPropertyName.of("spring")); + assertThat(spring).isNotNull(); + assertThat(spring.getValue()).isEqualTo("boot"); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCachingTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCachingTests.java index 5d25acc5ff1..6e7a7f12b02 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCachingTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCachingTests.java @@ -20,6 +20,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -108,7 +109,7 @@ class ConfigurationPropertySourcesCachingTests { new ConfigurationPropertySourcesCaching(null).enable(); } - private ConfigurationPropertyCaching getCaching(int index) { + private @Nullable ConfigurationPropertyCaching getCaching(int index) { return CachingConfigurationPropertySource.find(this.sources.get(index)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java index 5ff89738470..9e75f206315 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.core.convert.ConversionFailedException; @@ -165,7 +166,7 @@ class ConfigurationPropertySourcesPropertyResolverTests { private final Map counts = new HashMap<>(); @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { incrementCount(name); return super.getProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java index ba0fb8d0e55..8fd2ce76f46 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -129,7 +130,7 @@ class ConfigurationPropertySourcesTests { sources.addFirst(new PropertySource("env", environment) { @Override - public String getProperty(String key) { + public @Nullable String getProperty(String key) { return this.source.getProperty(key); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyStateTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyStateTests.java index abd1b9e33d3..ea436c7b30e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyStateTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyStateTests.java @@ -33,12 +33,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ConfigurationPropertyStateTests { @Test + @SuppressWarnings("NullAway") // Test null check void searchWhenIterableIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyState.search(null, (e) -> true)) .withMessageContaining("'source' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void searchWhenPredicateIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> ConfigurationPropertyState.search(Collections.emptyList(), null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyTests.java index da0141837b1..09bf65eae6e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.context.properties.source; +import java.util.Objects; + import org.junit.jupiter.api.Test; import org.springframework.boot.origin.Origin; @@ -36,15 +38,18 @@ class ConfigurationPropertyTests { private static final ConfigurationPropertyName NAME = ConfigurationPropertyName.of("foo"); - private final ConfigurationPropertySource source = ConfigurationPropertySource.from(mock(PropertySource.class)); + private final ConfigurationPropertySource source = Objects + .requireNonNull(ConfigurationPropertySource.from(mock(PropertySource.class))); @Test + @SuppressWarnings("NullAway") // Test null check void createWhenNameIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationProperty(null, "bar", null)) .withMessageContaining("'name' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenValueIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationProperty(NAME, null, null)) .withMessageContaining("'value' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSourceTests.java index 0676b0ca846..4b1d4f23446 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSourceTests.java @@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class FilteredConfigurationPropertiesSourceTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenSourceIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new FilteredConfigurationPropertiesSource(null, Objects::nonNull)) @@ -39,6 +40,7 @@ class FilteredConfigurationPropertiesSourceTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenFilterIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new FilteredConfigurationPropertiesSource(new MockConfigurationPropertySource(), null)) @@ -50,10 +52,16 @@ class FilteredConfigurationPropertiesSourceTests { ConfigurationPropertySource source = createTestSource(); ConfigurationPropertySource filtered = source.filter(this::noBrackets); ConfigurationPropertyName name = ConfigurationPropertyName.of("a"); - assertThat(source.getConfigurationProperty(name).getValue()).isEqualTo("1"); - assertThat(filtered.getConfigurationProperty(name).getValue()).isEqualTo("1"); + ConfigurationProperty configurationProperty = source.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("1"); + ConfigurationProperty configurationProperty2 = filtered.getConfigurationProperty(name); + assertThat(configurationProperty2).isNotNull(); + assertThat(configurationProperty2.getValue()).isEqualTo("1"); ConfigurationPropertyName bracketName = ConfigurationPropertyName.of("a[1]"); - assertThat(source.getConfigurationProperty(bracketName).getValue()).isEqualTo("2"); + ConfigurationProperty configurationProperty3 = source.getConfigurationProperty(bracketName); + assertThat(configurationProperty3).isNotNull(); + assertThat(configurationProperty3.getValue()).isEqualTo("2"); assertThat(filtered.getConfigurationProperty(bracketName)).isNull(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSourceTests.java index 241e9888133..b242610c6fd 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSourceTests.java @@ -62,7 +62,9 @@ class FilteredIterableConfigurationPropertiesSourceTests extends FilteredConfigu IterableConfigurationPropertySource testSource = (IterableConfigurationPropertySource) createTestSource(); Map map = new LinkedHashMap<>(); for (ConfigurationPropertyName name : testSource) { - map.put(name.toString(), testSource.getConfigurationProperty(name).getValue()); + ConfigurationProperty configurationProperty = testSource.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + map.put(name.toString(), configurationProperty.getValue()); } PropertySource propertySource = new OriginTrackedMapPropertySource("test", map, true); SpringConfigurationPropertySource source = SpringConfigurationPropertySource.from(propertySource); @@ -79,7 +81,9 @@ class FilteredIterableConfigurationPropertiesSourceTests extends FilteredConfigu IterableConfigurationPropertySource testSource = (IterableConfigurationPropertySource) createTestSource(); Map map = new LinkedHashMap<>(); for (ConfigurationPropertyName name : testSource) { - map.put(name.toString(), testSource.getConfigurationProperty(name).getValue()); + ConfigurationProperty configurationProperty = testSource.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + map.put(name.toString(), configurationProperty.getValue()); } PropertySource propertySource = new OriginTrackedMapPropertySource("test", map, true); SpringConfigurationPropertySource source = SpringConfigurationPropertySource.from(propertySource); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/KnownAncestorsConfigurationPropertySource.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/KnownAncestorsConfigurationPropertySource.java index 90ff6642a41..85a5e0b28c5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/KnownAncestorsConfigurationPropertySource.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/KnownAncestorsConfigurationPropertySource.java @@ -19,6 +19,8 @@ package org.springframework.boot.context.properties.source; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import static org.assertj.core.api.Assertions.assertThat; class KnownAncestorsConfigurationPropertySource implements ConfigurationPropertySource { @@ -26,7 +28,7 @@ class KnownAncestorsConfigurationPropertySource implements ConfigurationProperty private final Map ancestors = new HashMap<>(); @Override - public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { + public @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySourceTests.java index 2d2ba135557..9ffcebbdcd8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySourceTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.source; import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -33,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class MapConfigurationPropertySourceTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenMapIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new MapConfigurationPropertySource(null)) .withMessageContaining("'map' must not be null"); @@ -49,6 +51,7 @@ class MapConfigurationPropertySourceTests { } @Test + @SuppressWarnings("NullAway") // Test null check void putAllWhenMapIsNullShouldThrowException() { MapConfigurationPropertySource source = new MapConfigurationPropertySource(); assertThatIllegalArgumentException().isThrownBy(() -> source.putAll(null)) @@ -101,7 +104,7 @@ class MapConfigurationPropertySourceTests { } - private Object getValue(ConfigurationPropertySource source, String name) { + private @Nullable Object getValue(ConfigurationPropertySource source, String name) { ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); return (property != null) ? property.getValue() : null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MockConfigurationPropertySource.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MockConfigurationPropertySource.java index da80b536da8..b1c807746c5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MockConfigurationPropertySource.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MockConfigurationPropertySource.java @@ -21,6 +21,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.origin.MockOrigin; import org.springframework.boot.origin.OriginTrackedValue; @@ -41,7 +43,7 @@ public class MockConfigurationPropertySource implements IterableConfigurationPro this(configurationPropertyName, value, null); } - public MockConfigurationPropertySource(String configurationPropertyName, Object value, String origin) { + public MockConfigurationPropertySource(String configurationPropertyName, Object value, @Nullable String origin) { put(ConfigurationPropertyName.of(configurationPropertyName), OriginTrackedValue.of(value, MockOrigin.of(origin))); } @@ -82,7 +84,7 @@ public class MockConfigurationPropertySource implements IterableConfigurationPro } @Override - public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { + public @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { OriginTrackedValue result = this.map.get(name); if (result == null) { result = findValue(name); @@ -90,7 +92,7 @@ public class MockConfigurationPropertySource implements IterableConfigurationPro return ConfigurationProperty.of(name, result); } - private OriginTrackedValue findValue(ConfigurationPropertyName name) { + private @Nullable OriginTrackedValue findValue(ConfigurationPropertyName name) { return this.map.get(name); } @@ -102,7 +104,7 @@ public class MockConfigurationPropertySource implements IterableConfigurationPro } @Override - public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { + public @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) { return MockConfigurationPropertySource.this.getConfigurationProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesExceptionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesExceptionTests.java index 2500d79edb3..332fc343edc 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesExceptionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesExceptionTests.java @@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException; class MutuallyExclusiveConfigurationPropertiesExceptionTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenConfiguredNamesIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(null, Arrays.asList("a", "b"))) @@ -50,6 +51,7 @@ class MutuallyExclusiveConfigurationPropertiesExceptionTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenMutuallyExclusiveNamesIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(Arrays.asList("a", "b"), null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySourceTests.java index cbd8fc4bfef..4f291f37f43 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySourceTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.context.properties.source; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -82,12 +83,12 @@ class PrefixedConfigurationPropertySourceTests { assertThat(prefixed).isSameAs(source); } - private ConfigurationPropertyName getName(ConfigurationPropertySource source, String name) { + private @Nullable ConfigurationPropertyName getName(ConfigurationPropertySource source, String name) { ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); return (property != null) ? property.getName() : null; } - private Object getValue(ConfigurationPropertySource source, String name) { + private @Nullable Object getValue(ConfigurationPropertySource source, String name) { ConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name)); return (property != null) ? property.getValue() : null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCacheTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCacheTests.java index acbc2905b78..dd473e67981 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCacheTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCacheTests.java @@ -22,6 +22,7 @@ import java.time.Instant; import java.time.ZoneOffset; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.source.ConfigurationPropertyCaching.CacheOverride; @@ -186,14 +187,14 @@ class SoftReferenceConfigurationPropertyCacheTests { */ class TestSoftReferenceConfigurationPropertyCache extends SoftReferenceConfigurationPropertyCache { - private Value value; + private @Nullable Value value; TestSoftReferenceConfigurationPropertyCache(boolean neverExpire) { super(neverExpire); } @Override - protected Value getValue() { + protected @Nullable Value getValue() { return this.value; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java index ca5a732a630..cb61be0a9cb 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.env.RandomValuePropertySource; @@ -41,6 +42,7 @@ import static org.mockito.Mockito.mock; class SpringConfigurationPropertySourceTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertySourceIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new SpringConfigurationPropertySource(null, false, mock(PropertyMapper.class))) @@ -59,7 +61,9 @@ class SpringConfigurationPropertySourceTests { mapper.addFromConfigurationProperty(name, "key2"); SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false, mapper); - assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("value2"); } @Test @@ -73,6 +77,7 @@ class SpringConfigurationPropertySourceTests { SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false, mapper); ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); assertThat(configurationProperty.getOrigin()).hasToString("\"key\" from property source \"test\""); assertThat(configurationProperty.getSource()).isEqualTo(adapter); } @@ -87,7 +92,9 @@ class SpringConfigurationPropertySourceTests { mapper.addFromConfigurationProperty(name, "key"); SpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false, mapper); - assertThat(adapter.getConfigurationProperty(name).getOrigin()).hasToString("TestOrigin key"); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getOrigin()).hasToString("TestOrigin key"); } @Test @@ -102,6 +109,7 @@ class SpringConfigurationPropertySourceTests { } @Test + @SuppressWarnings("NullAway") // Test null check void fromWhenPropertySourceIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> SpringConfigurationPropertySource.from(null)) .withMessageContaining("'source' must not be null"); @@ -112,7 +120,7 @@ class SpringConfigurationPropertySourceTests { PropertySource propertySource = new PropertySource<>("test", new Object()) { @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return null; } @@ -242,7 +250,7 @@ class SpringConfigurationPropertySourceTests { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { name = name.toLowerCase(Locale.ROOT); if (!name.startsWith(this.prefix)) { return null; @@ -267,7 +275,7 @@ class SpringConfigurationPropertySourceTests { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return this.propertySource.getProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java index e74108a7026..e755d1c7f41 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.context.properties.source; import java.util.Collections; import java.util.Iterator; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.env.RandomValuePropertySource; @@ -41,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class SpringConfigurationPropertySourcesTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertySourcesIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new SpringConfigurationPropertySources(null)) .withMessageContaining("'sources' must not be null"); @@ -52,7 +54,9 @@ class SpringConfigurationPropertySourcesTests { sources.addFirst(new MapPropertySource("test", Collections.singletonMap("a", "b"))); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("a"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("b"); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("b"); assertThat(iterator.hasNext()).isFalse(); } @@ -63,7 +67,9 @@ class SpringConfigurationPropertySourcesTests { Collections.singletonMap("SERVER_PORT", "1234"))); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("1234"); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("1234"); assertThat(iterator.hasNext()).isFalse(); } @@ -75,7 +81,9 @@ class SpringConfigurationPropertySourcesTests { Collections.singletonMap("SERVER_PORT", "1234"))); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("1234"); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("1234"); assertThat(iterator.hasNext()).isFalse(); } @@ -86,7 +94,9 @@ class SpringConfigurationPropertySourcesTests { .addLast(new SystemEnvironmentPropertySource("override", Collections.singletonMap("server.port", "1234"))); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("1234"); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("1234"); assertThat(iterator.hasNext()).isFalse(); } @@ -109,10 +119,15 @@ class SpringConfigurationPropertySourcesTests { sources.addLast(new MapPropertySource("test2", Collections.singletonMap("a", "b"))); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("server.port"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("1234"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isEqualTo("4567"); - assertThat(iterator.next().getConfigurationProperty(ConfigurationPropertyName.of("a")).getValue()) - .isEqualTo("b"); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("1234"); + configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("4567"); + configurationProperty = iterator.next().getConfigurationProperty(ConfigurationPropertyName.of("a")); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("b"); assertThat(iterator.hasNext()).isFalse(); } @@ -125,7 +140,7 @@ class SpringConfigurationPropertySourcesTests { sources.addFirst(new PropertySource("env", environment) { @Override - public String getProperty(String key) { + public @Nullable String getProperty(String key) { return this.source.getProperty(key); } @@ -155,11 +170,17 @@ class SpringConfigurationPropertySourcesTests { ConfigurationPropertyName name = ConfigurationPropertyName.of("a"); MapPropertySource source1 = new MapPropertySource("test", Collections.singletonMap("a", "s1")); sources.addLast(source1); - assertThat(configurationSources.iterator().next().getConfigurationProperty(name).getValue()).isEqualTo("s1"); + ConfigurationProperty configurationProperty = configurationSources.iterator() + .next() + .getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("s1"); MapPropertySource source2 = new MapPropertySource("test", Collections.singletonMap("a", "s2")); sources.remove("test"); sources.addLast(source2); - assertThat(configurationSources.iterator().next().getConfigurationProperty(name).getValue()).isEqualTo("s2"); + configurationProperty = configurationSources.iterator().next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("s2"); } @Test // gh-21659 @@ -168,7 +189,9 @@ class SpringConfigurationPropertySourcesTests { sources.addFirst(new RandomValuePropertySource()); Iterator iterator = new SpringConfigurationPropertySources(sources).iterator(); ConfigurationPropertyName name = ConfigurationPropertyName.of("random.int"); - assertThat(iterator.next().getConfigurationProperty(name).getValue()).isNotNull(); + ConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isNotNull(); assertThat(iterator.hasNext()).isFalse(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java index a1408a4e8e3..aeef71b022c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java @@ -23,6 +23,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.env.OriginTrackedMapPropertySource; @@ -48,6 +49,7 @@ import static org.mockito.Mockito.mock; class SpringIterableConfigurationPropertySourceTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertySourceIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new SpringIterableConfigurationPropertySource(null, false, mock(PropertyMapper.class))) @@ -87,7 +89,9 @@ class SpringIterableConfigurationPropertySourceTests { mapper.addFromConfigurationProperty(name, "key2"); SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, false, mapper); - assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("value2"); } @Test @@ -103,7 +107,9 @@ class SpringIterableConfigurationPropertySourceTests { SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, false, mapper); ConfigurationPropertyName name = ConfigurationPropertyName.of("my.key"); - assertThat(adapter.getConfigurationProperty(name).getValue()).isEqualTo("value2"); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getValue()).isEqualTo("value2"); } @Test @@ -116,8 +122,9 @@ class SpringIterableConfigurationPropertySourceTests { mapper.addFromConfigurationProperty(name, "key"); SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, false, mapper); - assertThat(adapter.getConfigurationProperty(name).getOrigin()) - .hasToString("\"key\" from property source \"test\""); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getOrigin()).hasToString("\"key\" from property source \"test\""); } @Test @@ -131,7 +138,9 @@ class SpringIterableConfigurationPropertySourceTests { mapper.addFromConfigurationProperty(name, "key"); SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, false, mapper); - assertThat(adapter.getConfigurationProperty(name).getOrigin()).hasToString("TestOrigin key"); + ConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name); + assertThat(configurationProperty).isNotNull(); + assertThat(configurationProperty.getOrigin()).hasToString("TestOrigin key"); } @Test @@ -185,10 +194,14 @@ class SpringIterableConfigurationPropertySourceTests { StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, source); SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource( propertySource, true, SystemEnvironmentPropertyMapper.INSTANCE, DefaultPropertyMapper.INSTANCE); - assertThat(adapter.getConfigurationProperty(ConfigurationPropertyName.of("test.value-upper")).getValue()) - .isEqualTo("upper"); - assertThat(adapter.getConfigurationProperty(ConfigurationPropertyName.of("test.value-lower")).getValue()) - .isEqualTo("lower"); + ConfigurationProperty valueUpper = adapter + .getConfigurationProperty(ConfigurationPropertyName.of("test.value-upper")); + assertThat(valueUpper).isNotNull(); + assertThat(valueUpper.getValue()).isEqualTo("upper"); + ConfigurationProperty valueLower = adapter + .getConfigurationProperty(ConfigurationPropertyName.of("test.value-lower")); + assertThat(valueLower).isNotNull(); + assertThat(valueLower.getValue()).isEqualTo("lower"); } @Test @@ -292,7 +305,7 @@ class SpringIterableConfigurationPropertySourceTests { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return this.propertySource.getProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/ApplicationConversionServiceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/ApplicationConversionServiceTests.java index 5dd236c4742..505b6e31bfa 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/ApplicationConversionServiceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/ApplicationConversionServiceTests.java @@ -23,6 +23,7 @@ import java.util.Optional; import java.util.Set; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.convert.ApplicationConversionService.ConverterBeanAdapter; @@ -40,6 +41,7 @@ import org.springframework.core.convert.converter.ConditionalConverter; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterFactory; import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.format.AnnotationFormatterFactory; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.format.Parser; @@ -175,20 +177,24 @@ class ApplicationConversionServiceTests { } @Test + @SuppressWarnings("unchecked") void sharedInstanceCannotBeModified() { ApplicationConversionService instance = (ApplicationConversionService) ApplicationConversionService .getSharedInstance(); - assertUnmodifiableExceptionThrown(() -> instance.addPrinter(null)); - assertUnmodifiableExceptionThrown(() -> instance.addParser(null)); - assertUnmodifiableExceptionThrown(() -> instance.addFormatter(null)); - assertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(null, null)); - assertUnmodifiableExceptionThrown(() -> instance.addConverter((Converter) null)); - assertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(null, null, null)); - assertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldAnnotation(null)); - assertUnmodifiableExceptionThrown(() -> instance.addConverter(null, null, null)); - assertUnmodifiableExceptionThrown(() -> instance.addConverter((GenericConverter) null)); - assertUnmodifiableExceptionThrown(() -> instance.addConverterFactory(null)); - assertUnmodifiableExceptionThrown(() -> instance.removeConvertible(null, null)); + Printer printer = mock(Printer.class); + Parser parser = mock(Parser.class); + assertUnmodifiableExceptionThrown(() -> instance.addPrinter(printer)); + assertUnmodifiableExceptionThrown(() -> instance.addParser(parser)); + assertUnmodifiableExceptionThrown(() -> instance.addFormatter(mock(Formatter.class))); + assertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(getClass(), mock(Formatter.class))); + assertUnmodifiableExceptionThrown(() -> instance.addConverter(mock(Converter.class))); + assertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(getClass(), printer, parser)); + assertUnmodifiableExceptionThrown( + () -> instance.addFormatterForFieldAnnotation(mock(AnnotationFormatterFactory.class))); + assertUnmodifiableExceptionThrown(() -> instance.addConverter(getClass(), getClass(), mock(Converter.class))); + assertUnmodifiableExceptionThrown(() -> instance.addConverter(mock(GenericConverter.class))); + assertUnmodifiableExceptionThrown(() -> instance.addConverterFactory(mock(ConverterFactory.class))); + assertUnmodifiableExceptionThrown(() -> instance.removeConvertible(getClass(), getClass())); } @Test @@ -323,12 +329,12 @@ class ApplicationConversionServiceTests { static class ExampleGenericConverter implements GenericConverter { @Override - public Set getConvertibleTypes() { + public @Nullable Set getConvertibleTypes() { return null; } @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { return null; } @@ -337,7 +343,7 @@ class ApplicationConversionServiceTests { static class ExampleConverter implements Converter { @Override - public Integer convert(String source) { + public @Nullable Integer convert(String source) { return null; } @@ -347,12 +353,12 @@ class ApplicationConversionServiceTests { @Override public String print(Integer object, Locale locale) { - return null; + return ""; } @Override public Integer parse(String text, Locale locale) throws ParseException { - return null; + return 1; } } @@ -361,7 +367,7 @@ class ApplicationConversionServiceTests { @Override public Integer parse(String text, Locale locale) throws ParseException { - return null; + return 1; } } @@ -370,7 +376,7 @@ class ApplicationConversionServiceTests { @Override public String print(Integer object, Locale locale) { - return null; + return ""; } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/ArrayToDelimitedStringConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/ArrayToDelimitedStringConverterTests.java index 0d965d16e10..689ec26b399 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/ArrayToDelimitedStringConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/ArrayToDelimitedStringConverterTests.java @@ -16,8 +16,10 @@ package org.springframework.boot.convert; +import java.lang.reflect.Field; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.Arguments; @@ -45,8 +47,9 @@ class ArrayToDelimitedStringConverterTests { void convertWhenHasDelimiterNoneShouldConvert(ConversionService conversionService) { Data data = new Data(); data.none = new String[] { "1", "2", "3" }; - String converted = (String) conversionService.convert(data.none, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "none"), 0), + Field field = ReflectionUtils.findField(Data.class, "none"); + assertThat(field).isNotNull(); + String converted = (String) conversionService.convert(data.none, TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("123"); } @@ -55,8 +58,9 @@ class ArrayToDelimitedStringConverterTests { void convertWhenHasDelimiterDashShouldConvert(ConversionService conversionService) { Data data = new Data(); data.dash = new String[] { "1", "2", "3" }; - String converted = (String) conversionService.convert(data.dash, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "dash"), 0), + Field field = ReflectionUtils.findField(Data.class, "dash"); + assertThat(field).isNotNull(); + String converted = (String) conversionService.convert(data.dash, TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("1-2-3"); } @@ -72,9 +76,10 @@ class ArrayToDelimitedStringConverterTests { void convertShouldConvertElements() { Data data = new Data(); data.type = new int[] { 1, 2, 3 }; + Field field = ReflectionUtils.findField(Data.class, "type"); + assertThat(field).isNotNull(); String converted = (String) new ApplicationConversionService().convert(data.type, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "type"), 0), - TypeDescriptor.valueOf(String.class)); + TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("1.2.3"); } @@ -86,13 +91,13 @@ class ArrayToDelimitedStringConverterTests { static class Data { @Delimiter(Delimiter.NONE) - String[] none; + String @Nullable [] none; @Delimiter("-") - String[] dash; + String @Nullable [] dash; @Delimiter(".") - int[] type; + int @Nullable [] type; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/CollectionToDelimitedStringConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/CollectionToDelimitedStringConverterTests.java index 20126c8b683..e3285cc8054 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/CollectionToDelimitedStringConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/CollectionToDelimitedStringConverterTests.java @@ -16,10 +16,12 @@ package org.springframework.boot.convert; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.Arguments; @@ -47,8 +49,9 @@ class CollectionToDelimitedStringConverterTests { void convertWhenHasDelimiterNoneShouldConvert(ConversionService conversionService) { Data data = new Data(); data.none = Arrays.asList("1", "2", "3"); - String converted = (String) conversionService.convert(data.none, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "none"), 0), + Field field = ReflectionUtils.findField(Data.class, "none"); + assertThat(field).isNotNull(); + String converted = (String) conversionService.convert(data.none, TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("123"); } @@ -57,8 +60,9 @@ class CollectionToDelimitedStringConverterTests { void convertWhenHasDelimiterDashShouldConvert(ConversionService conversionService) { Data data = new Data(); data.dash = Arrays.asList("1", "2", "3"); - String converted = (String) conversionService.convert(data.dash, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "dash"), 0), + Field field = ReflectionUtils.findField(Data.class, "dash"); + assertThat(field).isNotNull(); + String converted = (String) conversionService.convert(data.dash, TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("1-2-3"); } @@ -74,9 +78,10 @@ class CollectionToDelimitedStringConverterTests { void convertShouldConvertElements() { Data data = new Data(); data.type = Arrays.asList(1, 2, 3); + Field field = ReflectionUtils.findField(Data.class, "type"); + assertThat(field).isNotNull(); String converted = (String) new ApplicationConversionService().convert(data.type, - TypeDescriptor.nested(ReflectionUtils.findField(Data.class, "type"), 0), - TypeDescriptor.valueOf(String.class)); + TypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class)); assertThat(converted).isEqualTo("1.2.3"); } @@ -88,13 +93,13 @@ class CollectionToDelimitedStringConverterTests { static class Data { @Delimiter(Delimiter.NONE) - List none; + @Nullable List none; @Delimiter("-") - List dash; + @Nullable List dash; @Delimiter(".") - List type; + @Nullable List type; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceArguments.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceArguments.java index d86a0b11a43..114afbf4cd2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceArguments.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceArguments.java @@ -19,6 +19,7 @@ package org.springframework.boot.convert; import java.util.function.Consumer; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -76,22 +77,23 @@ public final class ConversionServiceArguments { } @Override - public boolean canConvert(Class sourceType, Class targetType) { + public boolean canConvert(@Nullable Class sourceType, Class targetType) { return this.delegate.canConvert(sourceType, targetType); } @Override - public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { + public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { return this.delegate.canConvert(sourceType, targetType); } @Override - public T convert(Object source, Class targetType) { + public @Nullable T convert(@Nullable Object source, Class targetType) { return this.delegate.convert(source, targetType); } @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, + TypeDescriptor targetType) { return this.delegate.convert(source, sourceType, targetType); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToArrayConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToArrayConverterTests.java index c1ed5e29cc8..d4046e51ace 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToArrayConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToArrayConverterTests.java @@ -16,10 +16,12 @@ package org.springframework.boot.convert; +import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.Arguments; @@ -44,22 +46,30 @@ class DelimitedStringToArrayConverterTests { @ConversionServiceTest void matchesWhenTargetIsNotAnnotatedShouldReturnTrue(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "noAnnotation"), 0); + Field field = ReflectionUtils.findField(Values.class, "noAnnotation"); + assertThat(field).isNotNull(); + TypeDescriptor targetType = TypeDescriptor.nested(field, 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToArrayConverter(conversionService).matches(sourceType, targetType)).isTrue(); } @ConversionServiceTest void matchesWhenHasAnnotationAndNonConvertibleElementTypeShouldReturnFalse(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "nonConvertibleElementType"), 0); + Field field = ReflectionUtils.findField(Values.class, "nonConvertibleElementType"); + assertThat(field).isNotNull(); + TypeDescriptor targetType = TypeDescriptor.nested(field, 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToArrayConverter(conversionService).matches(sourceType, targetType)).isFalse(); } @ConversionServiceTest void convertWhenHasDelimiterOfNoneShouldReturnWholeString(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "delimiterNone"), 0); + Field field = ReflectionUtils.findField(Values.class, "delimiterNone"); + assertThat(field).isNotNull(); + TypeDescriptor targetType = TypeDescriptor.nested(field, 0); + assertThat(targetType).isNotNull(); String[] converted = (String[]) conversionService.convert("a,b,c", sourceType, targetType); assertThat(converted).containsExactly("a,b,c"); } @@ -67,8 +77,10 @@ class DelimitedStringToArrayConverterTests { @Test void matchesWhenHasAnnotationAndConvertibleElementTypeShouldReturnTrue() { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "convertibleElementType"), 0); + Field field = ReflectionUtils.findField(Values.class, "convertibleElementType"); + assertThat(field).isNotNull(); + TypeDescriptor targetType = TypeDescriptor.nested(field, 0); + assertThat(targetType).isNotNull(); assertThat( new DelimitedStringToArrayConverter(new ApplicationConversionService()).matches(sourceType, targetType)) .isTrue(); @@ -77,8 +89,10 @@ class DelimitedStringToArrayConverterTests { @Test void convertWhenHasConvertibleElementTypeShouldReturnConvertedType() { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "convertibleElementType"), 0); + Field field = ReflectionUtils.findField(Values.class, "convertibleElementType"); + assertThat(field).isNotNull(); + TypeDescriptor targetType = TypeDescriptor.nested(field, 0); + assertThat(targetType).isNotNull(); Integer[] converted = (Integer[]) new ApplicationConversionService().convert(" 1 | 2| 3 ", sourceType, targetType); assertThat(converted).containsExactly(1, 2, 3); @@ -91,16 +105,16 @@ class DelimitedStringToArrayConverterTests { static class Values { - List noAnnotation; + @Nullable List noAnnotation; @Delimiter("|") - Integer[] convertibleElementType; + Integer @Nullable [] convertibleElementType; @Delimiter("|") - NonConvertible[] nonConvertibleElementType; + NonConvertible @Nullable [] nonConvertibleElementType; @Delimiter(Delimiter.NONE) - String[] delimiterNone; + String @Nullable [] delimiterNone; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToCollectionConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToCollectionConverterTests.java index bf4b7063e4a..01e90a84925 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToCollectionConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToCollectionConverterTests.java @@ -16,11 +16,13 @@ package org.springframework.boot.convert; +import java.lang.reflect.Field; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.Arguments; @@ -45,7 +47,8 @@ class DelimitedStringToCollectionConverterTests { @ConversionServiceTest void matchesWhenTargetIsNotAnnotatedShouldReturnTrue(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "noAnnotation"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("noAnnotation"), 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType)) .isTrue(); } @@ -53,7 +56,8 @@ class DelimitedStringToCollectionConverterTests { @ConversionServiceTest void matchesWhenHasAnnotationAndNoElementTypeShouldReturnTrue(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "noElementType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("noElementType"), 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType)) .isTrue(); } @@ -61,8 +65,8 @@ class DelimitedStringToCollectionConverterTests { @ConversionServiceTest void matchesWhenHasAnnotationAndNonConvertibleElementTypeShouldReturnFalse(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "nonConvertibleElementType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("nonConvertibleElementType"), 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType)) .isFalse(); } @@ -71,7 +75,8 @@ class DelimitedStringToCollectionConverterTests { @SuppressWarnings("unchecked") void convertWhenHasNoElementTypeShouldReturnTrimmedString(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "noElementType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("noElementType"), 0); + assertThat(targetType).isNotNull(); Collection converted = (Collection) conversionService.convert(" a | b| c ", sourceType, targetType); assertThat(converted).containsExactly("a", "b", "c"); @@ -81,7 +86,8 @@ class DelimitedStringToCollectionConverterTests { @SuppressWarnings("unchecked") void convertWhenHasDelimiterOfNoneShouldReturnWholeString(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "delimiterNone"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("delimiterNone"), 0); + assertThat(targetType).isNotNull(); List converted = (List) conversionService.convert("a,b,c", sourceType, targetType); assertThat(converted).containsExactly("a,b,c"); } @@ -90,7 +96,8 @@ class DelimitedStringToCollectionConverterTests { @ConversionServiceTest void convertWhenHasCollectionObjectTypeShouldUseCollectionObjectType(ConversionService conversionService) { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor.nested(ReflectionUtils.findField(Values.class, "specificType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("specificType"), 0); + assertThat(targetType).isNotNull(); MyCustomList converted = (MyCustomList) conversionService.convert("a*b", sourceType, targetType); assertThat(converted).containsExactly("a", "b"); @@ -99,8 +106,8 @@ class DelimitedStringToCollectionConverterTests { @Test void matchesWhenHasAnnotationAndConvertibleElementTypeShouldReturnTrue() { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "convertibleElementType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("convertibleElementType"), 0); + assertThat(targetType).isNotNull(); assertThat(new DelimitedStringToCollectionConverter(new ApplicationConversionService()).matches(sourceType, targetType)) .isTrue(); @@ -110,13 +117,19 @@ class DelimitedStringToCollectionConverterTests { @SuppressWarnings("unchecked") void convertWhenHasConvertibleElementTypeShouldReturnConvertedType() { TypeDescriptor sourceType = TypeDescriptor.valueOf(String.class); - TypeDescriptor targetType = TypeDescriptor - .nested(ReflectionUtils.findField(Values.class, "convertibleElementType"), 0); + TypeDescriptor targetType = TypeDescriptor.nested(getField("convertibleElementType"), 0); + assertThat(targetType).isNotNull(); List converted = (List) new ApplicationConversionService().convert(" 1 | 2| 3 ", sourceType, targetType); assertThat(converted).containsExactly(1, 2, 3); } + private Field getField(String fieldName) { + Field field = ReflectionUtils.findField(Values.class, fieldName); + assertThat(field).isNotNull(); + return field; + } + static Stream conversionServices() { return ConversionServiceArguments .with((service) -> service.addConverter(new DelimitedStringToCollectionConverter(service))); @@ -124,23 +137,23 @@ class DelimitedStringToCollectionConverterTests { static class Values { - List noAnnotation; + @Nullable List noAnnotation; @SuppressWarnings("rawtypes") @Delimiter("|") - List noElementType; + @Nullable List noElementType; @Delimiter("|") - List convertibleElementType; + @Nullable List convertibleElementType; @Delimiter("|") - List nonConvertibleElementType; + @Nullable List nonConvertibleElementType; @Delimiter(Delimiter.NONE) - List delimiterNone; + @Nullable List delimiterNone; @Delimiter("*") - MyCustomList specificType; + @Nullable MyCustomList specificType; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/DurationStyleTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/DurationStyleTests.java index 6f7ef334920..9a94eb48624 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/DurationStyleTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/DurationStyleTests.java @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class DurationStyleTests { @Test + @SuppressWarnings("NullAway") // Test null check void detectAndParseWhenValueIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.detectAndParse(null)) .withMessageContaining("'value' must not be null"); @@ -207,8 +208,11 @@ class DurationStyleTests { @Test void parseSimpleWhenUnknownUnitShouldThrowException() { - assertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.SIMPLE.parse("10mb")) - .satisfies((ex) -> assertThat(ex.getCause().getMessage()).isEqualTo("Unknown unit 'mb'")); + assertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.SIMPLE.parse("10mb")).satisfies((ex) -> { + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + assertThat(cause.getMessage()).isEqualTo("Unknown unit 'mb'"); + }); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/InetAddressFormatterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/InetAddressFormatterTests.java index 345a34558bf..35d87cda0c4 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/InetAddressFormatterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/InetAddressFormatterTests.java @@ -49,6 +49,7 @@ class InetAddressFormatterTests { void convertFromStringToInetAddressShouldConvert(ConversionService conversionService) { assumingThat(isResolvable("example.com"), () -> { InetAddress converted = conversionService.convert("example.com", InetAddress.class); + assertThat(converted).isNotNull(); assertThat(converted.toString()).startsWith("example.com"); }); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java index 0d596f8e5b1..a4339c9d5d8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java @@ -18,6 +18,8 @@ package org.springframework.boot.convert; import java.util.Collections; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.TypeDescriptor; import org.springframework.util.unit.DataSize; @@ -38,7 +40,7 @@ public final class MockDataSizeTypeDescriptor { } @SuppressWarnings({ "rawtypes", "unchecked" }) - public static TypeDescriptor get(DataUnit unit) { + public static TypeDescriptor get(@Nullable DataUnit unit) { TypeDescriptor descriptor = mock(TypeDescriptor.class); if (unit != null) { DataSizeUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap("value", unit), diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDurationTypeDescriptor.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDurationTypeDescriptor.java index 6e279fb1eb8..7a3cbbc15aa 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDurationTypeDescriptor.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockDurationTypeDescriptor.java @@ -20,6 +20,8 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Collections; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.TypeDescriptor; @@ -38,7 +40,7 @@ public final class MockDurationTypeDescriptor { } @SuppressWarnings({ "rawtypes", "unchecked" }) - public static TypeDescriptor get(ChronoUnit unit, DurationStyle style) { + public static TypeDescriptor get(@Nullable ChronoUnit unit, @Nullable DurationStyle style) { TypeDescriptor descriptor = mock(TypeDescriptor.class); if (unit != null) { DurationUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap("value", unit), diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockPeriodTypeDescriptor.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockPeriodTypeDescriptor.java index 1fc54f900bd..fa8a2af01b6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/MockPeriodTypeDescriptor.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/MockPeriodTypeDescriptor.java @@ -20,6 +20,8 @@ import java.time.Period; import java.time.temporal.ChronoUnit; import java.util.Collections; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.TypeDescriptor; @@ -39,7 +41,7 @@ public final class MockPeriodTypeDescriptor { } @SuppressWarnings({ "rawtypes", "unchecked" }) - public static TypeDescriptor get(ChronoUnit unit, PeriodStyle style) { + public static TypeDescriptor get(@Nullable ChronoUnit unit, @Nullable PeriodStyle style) { TypeDescriptor descriptor = mock(TypeDescriptor.class); if (unit != null) { PeriodUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap("value", unit), diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java index 2df11c2d46d..eb314963451 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.convert; import java.util.Collections; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.annotation.AnnotationUtils; @@ -52,12 +53,13 @@ class NumberToDataSizeConverterTests { assertThat(convert(conversionService, -10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(-10)); } - private DataSize convert(ConversionService conversionService, Integer source) { + private @Nullable DataSize convert(ConversionService conversionService, Integer source) { return conversionService.convert(source, DataSize.class); } @SuppressWarnings({ "rawtypes", "unchecked" }) - private DataSize convert(ConversionService conversionService, Integer source, DataUnit defaultUnit) { + private @Nullable DataSize convert(ConversionService conversionService, Integer source, + @Nullable DataUnit defaultUnit) { TypeDescriptor targetType = mock(TypeDescriptor.class); if (defaultUnit != null) { DataSizeUnit unitAnnotation = AnnotationUtils diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDurationConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDurationConverterTests.java index 094e5e1dfc4..35ed92836c7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDurationConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDurationConverterTests.java @@ -21,6 +21,7 @@ import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.annotation.AnnotationUtils; @@ -52,12 +53,13 @@ class NumberToDurationConverterTests { assertThat(convert(conversionService, -10, ChronoUnit.SECONDS)).hasSeconds(-10); } - private Duration convert(ConversionService conversionService, Integer source) { + private @Nullable Duration convert(ConversionService conversionService, Integer source) { return conversionService.convert(source, Duration.class); } @SuppressWarnings({ "rawtypes", "unchecked" }) - private Duration convert(ConversionService conversionService, Integer source, ChronoUnit defaultUnit) { + private @Nullable Duration convert(ConversionService conversionService, Integer source, + @Nullable ChronoUnit defaultUnit) { TypeDescriptor targetType = mock(TypeDescriptor.class); if (defaultUnit != null) { DurationUnit unitAnnotation = AnnotationUtils diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToPeriodConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToPeriodConverterTests.java index 621012f9228..57159c91e5c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToPeriodConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToPeriodConverterTests.java @@ -21,6 +21,7 @@ import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.annotation.AnnotationUtils; @@ -58,12 +59,13 @@ class NumberToPeriodConverterTests { assertThat(convert(conversionService, -10, ChronoUnit.YEARS)).hasYears(-10); } - private Period convert(ConversionService conversionService, Integer source) { + private @Nullable Period convert(ConversionService conversionService, Integer source) { return conversionService.convert(source, Period.class); } @SuppressWarnings({ "rawtypes", "unchecked" }) - private Period convert(ConversionService conversionService, Integer source, ChronoUnit defaultUnit) { + private @Nullable Period convert(ConversionService conversionService, Integer source, + @Nullable ChronoUnit defaultUnit) { TypeDescriptor targetType = mock(TypeDescriptor.class); if (defaultUnit != null) { PeriodUnit unitAnnotation = AnnotationUtils diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodStyleTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodStyleTests.java index 122f4508a57..27f093a7ea8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodStyleTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodStyleTests.java @@ -34,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class PeriodStyleTests { @Test + @SuppressWarnings("NullAway") // Test null check void detectAndParseWhenValueIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.detectAndParse(null)) .withMessageContaining("'value' must not be null"); @@ -184,9 +185,11 @@ class PeriodStyleTests { @Test void parseSimpleWhenUnknownUnitShouldThrowException() { - assertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.SIMPLE.parse("10x")) - .satisfies( - (ex) -> assertThat(ex.getCause().getMessage()).isEqualTo("Does not match simple period pattern")); + assertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.SIMPLE.parse("10x")).satisfies((ex) -> { + Throwable cause = ex.getCause(); + assertThat(cause).isNotNull(); + assertThat(cause.getMessage()).isEqualTo("Does not match simple period pattern"); + }); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java index 95c479b9155..599bfb74150 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.convert; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.convert.ConversionFailedException; @@ -98,11 +99,11 @@ class StringToDataSizeConverterTests { assertThat(convert(conversionService, "")).isNull(); } - private DataSize convert(ConversionService conversionService, String source) { + private @Nullable DataSize convert(ConversionService conversionService, String source) { return conversionService.convert(source, DataSize.class); } - private DataSize convert(ConversionService conversionService, String source, DataUnit unit) { + private @Nullable DataSize convert(ConversionService conversionService, String source, @Nullable DataUnit unit) { return (DataSize) conversionService.convert(source, TypeDescriptor.forObject(source), MockDataSizeTypeDescriptor.get(unit)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDurationConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDurationConverterTests.java index 50711f0790e..9fb539f5b41 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDurationConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDurationConverterTests.java @@ -20,6 +20,7 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.convert.ConversionFailedException; @@ -137,11 +138,12 @@ class StringToDurationConverterTests { assertThat(convert(conversionService, "")).isNull(); } - private Duration convert(ConversionService conversionService, String source) { + private @Nullable Duration convert(ConversionService conversionService, String source) { return conversionService.convert(source, Duration.class); } - private Duration convert(ConversionService conversionService, String source, ChronoUnit unit, DurationStyle style) { + private @Nullable Duration convert(ConversionService conversionService, String source, @Nullable ChronoUnit unit, + @Nullable DurationStyle style) { return (Duration) conversionService.convert(source, TypeDescriptor.forObject(source), MockDurationTypeDescriptor.get(unit, style)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java index 466360a9e2e..29197258cc3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.provider.Arguments; @@ -38,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; class StringToFileConverterTests { @TempDir + @SuppressWarnings("NullAway.Init") File temp; @ConversionServiceTest @@ -48,19 +50,21 @@ class StringToFileConverterTests { @ConversionServiceTest void convertWhenFilePrefixedReturnsFile(ConversionService conversionService) { - assertThat(convert(conversionService, "file:" + this.temp.getAbsolutePath() + "/test").getAbsoluteFile()) - .isEqualTo(new File(this.temp, "test").getAbsoluteFile()); + File file = convert(conversionService, "file:" + this.temp.getAbsolutePath() + "/test"); + assertThat(file).isNotNull(); + assertThat(file.getAbsoluteFile()).isEqualTo(new File(this.temp, "test").getAbsoluteFile()); } @ConversionServiceTest @WithResource(name = "com/example/test-file.txt", content = "test content") void convertWhenClasspathPrefixedReturnsFile(ConversionService conversionService) throws IOException { String resource = new ClassPathResource("com/example/test-file.txt").getURL().getFile(); - assertThat(convert(conversionService, "classpath:com/example/test-file.txt").getAbsoluteFile()) - .isEqualTo(new File(resource).getAbsoluteFile()); + File file = convert(conversionService, "classpath:com/example/test-file.txt"); + assertThat(file).isNotNull(); + assertThat(file.getAbsoluteFile()).isEqualTo(new File(resource).getAbsoluteFile()); } - private File convert(ConversionService conversionService, String source) { + private @Nullable File convert(ConversionService conversionService, String source) { return conversionService.convert(source, File.class); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToPeriodConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToPeriodConverterTests.java index 20f11ab30d8..bc0f70dfa8a 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToPeriodConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/convert/StringToPeriodConverterTests.java @@ -20,6 +20,7 @@ import java.time.Period; import java.time.temporal.ChronoUnit; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.params.provider.Arguments; import org.springframework.core.convert.ConversionService; @@ -103,11 +104,12 @@ class StringToPeriodConverterTests { assertThat(convert(conversionService, "-10", ChronoUnit.YEARS, null)).isEqualTo(Period.ofYears(-10)); } - private Period convert(ConversionService conversionService, String source) { + private @Nullable Period convert(ConversionService conversionService, String source) { return conversionService.convert(source, Period.class); } - private Period convert(ConversionService conversionService, String source, ChronoUnit unit, PeriodStyle style) { + private @Nullable Period convert(ConversionService conversionService, String source, @Nullable ChronoUnit unit, + @Nullable PeriodStyle style) { return (Period) conversionService.convert(source, TypeDescriptor.forObject(source), MockPeriodTypeDescriptor.get(unit, style)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzerTests.java index ab599c0d546..61599012ad2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.diagnostics; import java.io.IOException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -79,7 +80,7 @@ class AbstractFailureAnalyzerTests { static class TestFailureAnalyzer extends AbstractFailureAnalyzer { @Override - protected FailureAnalysis analyze(Throwable rootFailure, Throwable cause) { + protected @Nullable FailureAnalysis analyze(Throwable rootFailure, Throwable cause) { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java index 8cfbb35039f..b2ab039bc1f 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.diagnostics; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,6 +42,7 @@ import static org.mockito.Mockito.times; @ExtendWith(OutputCaptureExtension.class) class FailureAnalyzersTests { + @SuppressWarnings("NullAway.Init") private static FailureAnalyzer failureAnalyzer; private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @@ -103,12 +105,13 @@ class FailureAnalyzersTests { static class BasicFailureAnalyzer implements FailureAnalyzer { @Override - public FailureAnalysis analyze(Throwable failure) { + public @Nullable FailureAnalysis analyze(Throwable failure) { return failureAnalyzer.analyze(failure); } } + @SuppressWarnings("NullAway") // Intentional NullPointerException static class BrokenInitializationFailureAnalyzer implements FailureAnalyzer { static { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzerTests.java index b0b47b4a334..254901445d1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.diagnostics.analyzer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.AotInitializerNotFoundException; @@ -33,6 +34,7 @@ class AotInitializerNotFoundFailureAnalyzerTests { @Test void shouldAnalyze() { FailureAnalysis analysis = analyze(); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).isEqualTo( "Startup with AOT mode enabled failed: AOT initializer class org.springframework.boot.diagnostics.analyzer.AotInitializerNotFoundFailureAnalyzerTests__ApplicationContextInitializer could not be found"); assertThat(analysis.getAction()).isEqualTo( @@ -43,7 +45,7 @@ class AotInitializerNotFoundFailureAnalyzerTests { \tIf you want to run the application in regular mode, remove the system property 'spring.aot.enabled'"""); } - private FailureAnalysis analyze() { + private @Nullable FailureAnalysis analyze() { return new AotInitializerNotFoundFailureAnalyzer() .analyze(new AotInitializerNotFoundException(AotInitializerNotFoundFailureAnalyzerTests.class, AotInitializerNotFoundFailureAnalyzerTests.class + "__ApplicationContextInitializer")); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java index 62551935ecb..50c2d9fa4b4 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java @@ -169,7 +169,7 @@ class BeanCurrentlyInCreationFailureAnalyzerTests { beanFactory.setAllowCircularReferences(allowCircularReferences); this.context.refresh(); fail("Expected failure did not occur"); - return null; + throw new AssertionError("This should not be reached"); } catch (Exception ex) { return ex; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java index 6d34502b86c..d0a304110cd 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.diagnostics.analyzer; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.support.BeanDefinitionOverrideException; @@ -40,6 +41,7 @@ class BeanDefinitionOverrideFailureAnalyzerTests { @Test void analyzeBeanDefinitionOverrideException() { FailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class); + assertThat(analysis).isNotNull(); String description = analysis.getDescription(); assertThat(description).contains("The bean 'testBean', defined in " + SecondConfiguration.class.getName() + ", could not be registered."); @@ -52,19 +54,20 @@ class BeanDefinitionOverrideFailureAnalyzerTests { context.registerBean("testBean", String.class, (Supplier) String::new); context.registerBean("testBean", String.class, (Supplier) String::new); }); + assertThat(analysis).isNotNull(); String description = analysis.getDescription(); assertThat(description) .isEqualTo("The bean 'testBean' could not be registered. A bean with that name has already" + " been defined and overriding is disabled."); } - private FailureAnalysis performAnalysis(Class configuration) { + private @Nullable FailureAnalysis performAnalysis(Class configuration) { BeanDefinitionOverrideException failure = createFailure(configuration); assertThat(failure).isNotNull(); return new BeanDefinitionOverrideFailureAnalyzer().analyze(failure); } - private BeanDefinitionOverrideException createFailure(Class configuration) { + private @Nullable BeanDefinitionOverrideException createFailure(Class configuration) { try { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.setAllowBeanDefinitionOverriding(false); @@ -78,14 +81,14 @@ class BeanDefinitionOverrideFailureAnalyzerTests { } } - private FailureAnalysis performAnalysis( + private @Nullable FailureAnalysis performAnalysis( ApplicationContextInitializer initializer) { BeanDefinitionOverrideException failure = createFailure(initializer); assertThat(failure).isNotNull(); return new BeanDefinitionOverrideFailureAnalyzer().analyze(failure); } - private BeanDefinitionOverrideException createFailure( + private @Nullable BeanDefinitionOverrideException createFailure( ApplicationContextInitializer initializer) { try { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzerTests.java index b676f155409..d62ebdac972 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzerTests.java @@ -63,7 +63,7 @@ class BeanNotOfRequiredTypeFailureAnalyzerTests { private Exception createFailure(Class configuration) { try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configuration)) { fail("Expected failure did not occur"); - return null; + throw new AssertionError("Should not be reached"); } catch (Exception ex) { return ex; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzerTests.java index 425a6a87420..1e9b91c80bc 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzerTests.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import jakarta.validation.constraints.Min; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; @@ -61,6 +62,7 @@ class BindFailureAnalyzerTests { @Test void bindExceptionDueToOtherFailure() { FailureAnalysis analysis = performAnalysis(GenericFailureConfiguration.class, "test.foo.value=alpha"); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("test.foo.value", "alpha", "\"test.foo.value\" from property source \"test\"", "failed to convert java.lang.String to int")); } @@ -68,6 +70,7 @@ class BindFailureAnalyzerTests { @Test void bindExceptionForUnknownValueInEnumListsValidValuesInAction() { FailureAnalysis analysis = performAnalysis(EnumFailureConfiguration.class, "test.foo.fruit=apple,strawberry"); + assertThat(analysis).isNotNull(); for (Fruit fruit : Fruit.values()) { assertThat(analysis.getAction()).contains(fruit.name()); } @@ -76,6 +79,7 @@ class BindFailureAnalyzerTests { @Test void bindExceptionWithNestedFailureShouldDisplayNestedMessage() { FailureAnalysis analysis = performAnalysis(NestedFailureConfiguration.class, "test.foo.value=hello"); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("test.foo.value", "hello", "\"test.foo.value\" from property source \"test\"", "java.lang.RuntimeException: This is a failure")); } @@ -84,6 +88,7 @@ class BindFailureAnalyzerTests { void bindExceptionDueToClassNotFoundConversionFailure() { FailureAnalysis analysis = performAnalysis(GenericFailureConfiguration.class, "test.foo.type=com.example.Missing"); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("test.foo.type", "com.example.Missing", "\"test.foo.type\" from property source \"test\"", "failed to convert java.lang.String to java.lang.Class (caused by java.lang.ClassNotFoundException: com.example.Missing")); @@ -92,6 +97,7 @@ class BindFailureAnalyzerTests { @Test void bindExceptionDueToMapConversionFailure() { FailureAnalysis analysis = performAnalysis(LoggingLevelFailureConfiguration.class, "logging.level=debug"); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("logging.level", "debug", "\"logging.level\" from property source \"test\"", "org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting " @@ -102,9 +108,11 @@ class BindFailureAnalyzerTests { @Test void bindExceptionWithSuppressedMissingParametersException() { BeanCreationException failure = createFailure(GenericFailureConfiguration.class, "test.foo.value=alpha"); + assertThat(failure).isNotNull(); failure.addSuppressed(new IllegalStateException( "Missing parameter names. Ensure that the compiler uses the '-parameters' flag")); FailureAnalysis analysis = new BindFailureAnalyzer().analyze(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .contains(failure("test.foo.value", "alpha", "\"test.foo.value\" from property source \"test\"", "failed to convert java.lang.String to int")) @@ -117,13 +125,13 @@ class BindFailureAnalyzerTests { reason); } - private FailureAnalysis performAnalysis(Class configuration, String... environment) { + private @Nullable FailureAnalysis performAnalysis(Class configuration, String... environment) { BeanCreationException failure = createFailure(configuration, environment); assertThat(failure).isNotNull(); return new BindFailureAnalyzer().analyze(failure); } - private BeanCreationException createFailure(Class configuration, String... environment) { + private @Nullable BeanCreationException createFailure(Class configuration, String... environment) { try { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); addEnvironment(context, environment); @@ -199,13 +207,13 @@ class BindFailureAnalyzerTests { @ConfigurationProperties("test.foo") static class UnboundElementsFailureProperties { - private List listValue; + private @Nullable List listValue; - List getListValue() { + @Nullable List getListValue() { return this.listValue; } - void setListValue(List listValue) { + void setListValue(@Nullable List listValue) { this.listValue = listValue; } @@ -216,7 +224,7 @@ class BindFailureAnalyzerTests { private int value; - private Class type; + private @Nullable Class type; int getValue() { return this.value; @@ -226,11 +234,11 @@ class BindFailureAnalyzerTests { this.value = value; } - Class getType() { + @Nullable Class getType() { return this.type; } - void setType(Class type) { + void setType(@Nullable Class type) { this.type = type; } @@ -239,13 +247,13 @@ class BindFailureAnalyzerTests { @ConfigurationProperties("test.foo") static class EnumFailureProperties { - private Set fruit; + private @Nullable Set fruit; - Set getFruit() { + @Nullable Set getFruit() { return this.fruit; } - void setFruit(Set fruit) { + void setFruit(@Nullable Set fruit) { this.fruit = fruit; } @@ -254,13 +262,13 @@ class BindFailureAnalyzerTests { @ConfigurationProperties("test.foo") static class NestedFailureProperties { - private String value; + private @Nullable String value; - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { throw new RuntimeException("This is a failure"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzerTests.java index d0baa9f2d43..1e5acadbbb1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzerTests.java @@ -23,6 +23,7 @@ import java.util.Map; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -63,6 +64,7 @@ class BindValidationFailureAnalyzerTests { @Test void bindExceptionWithFieldErrorsDueToValidationFailure() { FailureAnalysis analysis = performAnalysis(FieldValidationFailureConfiguration.class); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("test.foo.foo", "null", "must not be null")) .contains(failure("test.foo.value", "0", "at least five")) .contains(failure("test.foo.nested.bar", "null", "must not be null")) @@ -73,12 +75,14 @@ class BindValidationFailureAnalyzerTests { @Test void bindExceptionWithOriginDueToValidationFailure() { FailureAnalysis analysis = performAnalysis(FieldValidationFailureConfiguration.class, "test.foo.value=4"); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains("Origin: \"test.foo.value\" from property source \"test\""); } @Test void bindExceptionWithObjectErrorsDueToValidationFailure() { FailureAnalysis analysis = performAnalysis(ObjectValidationFailureConfiguration.class); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains("Reason: This object could not be bound."); } @@ -89,6 +93,7 @@ class BindValidationFailureAnalyzerTests { cause.addError(new FieldError("test", "value", "must not be null")); BeanCreationException rootFailure = new BeanCreationException("bean creation failure", cause); FailureAnalysis analysis = new BindValidationFailureAnalyzer().analyze(rootFailure, rootFailure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(failure("test.value", "null", "must not be null")); } @@ -96,13 +101,13 @@ class BindValidationFailureAnalyzerTests { return String.format("Property: %s%n Value: \"%s\"%n Reason: %s", property, value, reason); } - private FailureAnalysis performAnalysis(Class configuration, String... environment) { + private @Nullable FailureAnalysis performAnalysis(Class configuration, String... environment) { BeanCreationException failure = createFailure(configuration, environment); assertThat(failure).isNotNull(); return new BindValidationFailureAnalyzer().analyze(failure); } - private BeanCreationException createFailure(Class configuration, String... environment) { + private @Nullable BeanCreationException createFailure(Class configuration, String... environment) { try { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); addEnvironment(context, environment); @@ -143,6 +148,7 @@ class BindValidationFailureAnalyzerTests { static class FieldValidationFailureProperties { @NotNull + @SuppressWarnings("NullAway.Init") private String foo; @Min(value = 5, message = "at least five") @@ -178,6 +184,7 @@ class BindValidationFailureAnalyzerTests { static class Nested { @NotNull + @SuppressWarnings("NullAway.Init") private String bar; String getBar() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzerTests.java index 78002c5abd8..83658218fd4 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzerTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.diagnostics.analyzer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; @@ -40,14 +41,16 @@ class InvalidConfigurationPropertyNameFailureAnalyzerTests { @Test void analysisWhenRootCauseIsBeanCreationFailureShouldContainBeanName() { BeanCreationException failure = createFailure(InvalidPrefixConfiguration.class); + assertThat(failure).isNotNull(); FailureAnalysis analysis = this.analyzer.analyze(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .contains(String.format("%n Invalid characters: %s%n Bean: %s%n Reason: %s", "'F', 'P'", "invalidPrefixProperties", "Canonical names should be kebab-case ('-' separated), " + "lowercase alpha-numeric characters and must start with a letter")); } - private BeanCreationException createFailure(Class configuration) { + private @Nullable BeanCreationException createFailure(Class configuration) { try { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(configuration); @@ -74,13 +77,13 @@ class InvalidConfigurationPropertyNameFailureAnalyzerTests { @ConfigurationProperties("FooPrefix") static class InvalidPrefixProperties { - private String value; + private @Nullable String value; - String getValue() { + @Nullable String getValue() { return this.value; } - void setValue(String value) { + void setValue(@Nullable String value) { this.value = value; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java index 33fab291ada..e9ebcd0d351 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.diagnostics.analyzer; import java.util.Collections; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; @@ -48,6 +49,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", "This is not valid."); FailureAnalysis analysis = new InvalidConfigurationPropertyValueFailureAnalyzer(null).analyze(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .contains("Invalid value 'invalid' for configuration property 'test.property'."); } @@ -59,6 +61,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertCommonParts(failure, analysis); assertThat(analysis.getAction()).contains("Review the value of the property with the provided reason."); assertThat(analysis.getDescription()).contains("Validation failed for the following reason") @@ -76,6 +79,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "com.example.test-property", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains("com.example.test-property") .contains("invalid") .contains("property source \"systemEnvironment\""); @@ -93,6 +97,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", null); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getAction()).contains("Review the value of the property."); assertThat(analysis.getDescription()).contains("No reason was provided.") .doesNotContain("Additionally, this property is also set"); @@ -112,6 +117,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.property", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertCommonParts(failure, analysis); assertThat(analysis.getAction()).contains("Review the value of the property with the provided reason."); assertThat(analysis.getDescription()) @@ -126,6 +132,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { InvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException( "test.key.not.defined", "invalid", "This is not valid."); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .contains("Invalid value 'invalid' for configuration property 'test.key.not.defined'."); } @@ -137,7 +144,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { assertThat(analysis.getCause()).isSameAs(failure); } - private FailureAnalysis performAnalysis(InvalidConfigurationPropertyValueException failure) { + private @Nullable FailureAnalysis performAnalysis(InvalidConfigurationPropertyValueException failure) { InvalidConfigurationPropertyValueFailureAnalyzer analyzer = new InvalidConfigurationPropertyValueFailureAnalyzer( this.environment); return analyzer.analyze(failure); @@ -157,7 +164,7 @@ class InvalidConfigurationPropertyValueFailureAnalyzerTests { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return this.propertySource.getProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzerTests.java index 658ff4197d6..bc40b687543 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.diagnostics.analyzer; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.diagnostics.FailureAnalysis; @@ -26,6 +27,7 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link MissingParameterNamesFailureAnalyzer}. @@ -38,6 +40,7 @@ class MissingParameterNamesFailureAnalyzerTests { void analyzeWhenMissingParametersExceptionReturnsFailure() throws Exception { MissingParameterNamesFailureAnalyzer analyzer = new MissingParameterNamesFailureAnalyzer(); FailureAnalysis analysis = analyzer.analyze(getSpringFrameworkMissingParameterException()); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .isEqualTo(String.format("Name for argument of type [java.lang.String] not specified, and parameter name " + "information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n")); @@ -48,6 +51,7 @@ class MissingParameterNamesFailureAnalyzerTests { void analyzeForMissingParametersWhenMissingParametersExceptionReturnsFailure() throws Exception { FailureAnalysis analysis = MissingParameterNamesFailureAnalyzer .analyzeForMissingParameters(getSpringFrameworkMissingParameterException()); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .isEqualTo(String.format("Name for argument of type [java.lang.String] not specified, and parameter name " + "information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n")); @@ -58,6 +62,7 @@ class MissingParameterNamesFailureAnalyzerTests { void analyzeForMissingParametersWhenInCauseReturnsFailure() throws Exception { RuntimeException exception = new RuntimeException("Badness", getSpringFrameworkMissingParameterException()); FailureAnalysis analysis = MissingParameterNamesFailureAnalyzer.analyzeForMissingParameters(exception); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .isEqualTo(String.format("Name for argument of type [java.lang.String] not specified, and parameter name " + "information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n%n" @@ -70,6 +75,7 @@ class MissingParameterNamesFailureAnalyzerTests { RuntimeException exception = new RuntimeException("Badness"); exception.addSuppressed(getSpringFrameworkMissingParameterException()); FailureAnalysis analysis = MissingParameterNamesFailureAnalyzer.analyzeForMissingParameters(exception); + assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) .isEqualTo(String.format("Name for argument of type [java.lang.String] not specified, and parameter name " + "information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n%n" @@ -89,7 +95,7 @@ class MissingParameterNamesFailureAnalyzerTests { Method method = getClass().getDeclaredMethod("example", String.class); MethodParameter parameter = new MethodParameter(method, 0); try { - resolver.resolveArgument(parameter, null, null, null); + resolver.resolveArgument(parameter, null, mock(NativeWebRequest.class), null); } catch (RuntimeException ex) { return ex; @@ -113,7 +119,7 @@ class MissingParameterNamesFailureAnalyzerTests { } @Override - protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) + protected @Nullable Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests.java index 296e983b2cf..716cbcbc4f5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests.java @@ -23,6 +23,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException; @@ -77,6 +78,7 @@ class MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests { new HashSet<>(Arrays.asList("com.example.a", "com.example.b")), new HashSet<>(Arrays.asList("com.example.a", "com.example.b"))); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getAction()).isEqualTo( "Update your configuration so that only one of the mutually exclusive properties is configured."); assertThat(analysis.getDescription()).contains(String.format( @@ -100,6 +102,7 @@ class MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests { new HashSet<>(Arrays.asList("com.example.a", "com.example.b")), new HashSet<>(Arrays.asList("com.example.a", "com.example.b"))); FailureAnalysis analysis = performAnalysis(failure); + assertThat(analysis).isNotNull(); assertThat(analysis.getAction()).isEqualTo( "Update your configuration so that only one of the mutually exclusive properties is configured."); assertThat(analysis.getDescription()).contains(String.format( @@ -112,7 +115,7 @@ class MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests { + "\tcom.example.b (originating from 'TestOrigin test-two')%n")); } - private FailureAnalysis performAnalysis(MutuallyExclusiveConfigurationPropertiesException failure) { + private @Nullable FailureAnalysis performAnalysis(MutuallyExclusiveConfigurationPropertiesException failure) { MutuallyExclusiveConfigurationPropertiesFailureAnalyzer analyzer = new MutuallyExclusiveConfigurationPropertiesFailureAnalyzer( this.environment); return analyzer.analyze(failure); @@ -128,7 +131,7 @@ class MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return this.propertySource.getProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java index 290216113ec..bbf1add709d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java @@ -76,7 +76,6 @@ class NoSuchMethodFailureAnalyzerTests { @Test void whenAMethodOnAClassIsMissingThenNoSuchMethodErrorIsAnalyzed() { Throwable failure = createFailureForMissingMethod(); - assertThat(failure).isNotNull(); FailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure); assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()) @@ -91,7 +90,6 @@ class NoSuchMethodFailureAnalyzerTests { @Test void whenAnInheritedMethodIsMissingThenNoSuchMethodErrorIsAnalyzed() { Throwable failure = createFailureForMissingInheritedMethod(); - assertThat(failure).isNotNull(); FailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure); assertThat(analysis).isNotNull(); assertThat(analysis.getDescription()).contains(R2dbcMappingContext.class.getName() + ".(") @@ -104,11 +102,12 @@ class NoSuchMethodFailureAnalyzerTests { assertThat(analysis.getAction()).contains("org.springframework.data.r2dbc.mapping.R2dbcMappingContext"); } + @SuppressWarnings("NullAway") // Deliberately trigger exception private Throwable createFailureForMissingMethod() { try { MimeType mimeType = new MimeType("application", "json"); mimeType.isMoreSpecific(null); - return null; + throw new AssertionError("Should not be reached"); } catch (Throwable ex) { return ex; @@ -118,7 +117,7 @@ class NoSuchMethodFailureAnalyzerTests { private Throwable createFailureForMissingInheritedMethod() { try { new R2dbcMappingContext(); - return null; + throw new AssertionError("Should not be reached"); } catch (Throwable ex) { return ex; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java index 35f170cc5d2..bd086845bc7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java @@ -146,15 +146,17 @@ class NoUniqueBeanDefinitionFailureAnalyzerTests { this.context.setParent(new AnnotationConfigApplicationContext(ParentProducer.class)); try { this.context.refresh(); + throw new AssertionError("Should not be reached"); } catch (BeanCreationException ex) { return ex; } - return null; } private FailureAnalysis analyzeFailure(Exception failure) { - return this.analyzer.analyze(failure); + FailureAnalysis analyze = this.analyzer.analyze(failure); + assertThat(analyze).isNotNull(); + return analyze; } private void assertFoundBeans(FailureAnalysis analysis) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzerTests.java index 0c382bd38c3..3ba1b95c6a5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzerTests.java @@ -45,14 +45,15 @@ class PatternParseFailureAnalyzerTests { private FailureAnalysis performAnalysis(String pattern) { PatternParseException failure = createFailure(pattern); - assertThat(failure).isNotNull(); - return new PatternParseFailureAnalyzer().analyze(failure); + FailureAnalysis analyze = new PatternParseFailureAnalyzer().analyze(failure); + assertThat(analyze).isNotNull(); + return analyze; } PatternParseException createFailure(String pattern) { try { this.parser.parse(pattern); - return null; + throw new AssertionError("Should not be reached"); } catch (PatternParseException ex) { return ex; diff --git a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzerTests.java index 8c1e1c9f73c..7d30325c435 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzerTests.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -69,8 +70,9 @@ class UnboundConfigurationPropertyFailureAnalyzerTests { private FailureAnalysis performAnalysis(Class configuration, String... environment) { BeanCreationException failure = createFailure(configuration, environment); - assertThat(failure).isNotNull(); - return new UnboundConfigurationPropertyFailureAnalyzer().analyze(failure); + FailureAnalysis analyze = new UnboundConfigurationPropertyFailureAnalyzer().analyze(failure); + assertThat(analyze).isNotNull(); + return analyze; } private BeanCreationException createFailure(Class configuration, String... environment) { @@ -80,7 +82,7 @@ class UnboundConfigurationPropertyFailureAnalyzerTests { context.register(configuration); context.refresh(); context.close(); - return null; + throw new AssertionError("Should not be reached"); } catch (BeanCreationException ex) { return ex; @@ -107,13 +109,13 @@ class UnboundConfigurationPropertyFailureAnalyzerTests { @ConfigurationProperties("test.foo") static class UnboundElementsFailureProperties { - private List listValue; + private @Nullable List listValue; - List getListValue() { + @Nullable List getListValue() { return this.listValue; } - void setListValue(List listValue) { + void setListValue(@Nullable List listValue) { this.listValue = listValue; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/env/ConfigTreePropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/env/ConfigTreePropertySourceTests.java index e99b4ef79af..d79faf6b501 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/env/ConfigTreePropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/env/ConfigTreePropertySourceTests.java @@ -29,10 +29,12 @@ import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.env.ConfigTreePropertySource.Option; import org.springframework.boot.env.ConfigTreePropertySource.Value; import org.springframework.boot.origin.TextResourceOrigin; +import org.springframework.boot.origin.TextResourceOrigin.Location; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -47,15 +49,18 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; class ConfigTreePropertySourceTests { @TempDir + @SuppressWarnings("NullAway.Init") Path directory; @Test + @SuppressWarnings("NullAway") // Test null check void createWhenNameIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(null, this.directory)) .withMessageContaining("name must contain"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenSourceIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource("test", null)) .withMessage("Property source must not be null"); @@ -134,17 +139,25 @@ class ConfigTreePropertySourceTests { ConfigTreePropertySource propertySource = getFlatPropertySource(); Path b = this.directory.resolve("b"); Files.delete(b); - assertThatIllegalStateException().isThrownBy(() -> propertySource.getProperty("b").toString()) - .withMessage("The property file '" + b + "' no longer exists"); + assertThatIllegalStateException().isThrownBy(() -> { + Value property = propertySource.getProperty("b"); + assertThat(property).isNotNull(); + property.toString(); + }).withMessage("The property file '" + b + "' no longer exists"); } @Test void getOriginFromFlatReturnsOrigin() throws Exception { ConfigTreePropertySource propertySource = getFlatPropertySource(); TextResourceOrigin origin = (TextResourceOrigin) propertySource.getOrigin("b"); - assertThat(origin.getResource().getFile()).isEqualTo(this.directory.resolve("b").toFile()); - assertThat(origin.getLocation().getLine()).isZero(); - assertThat(origin.getLocation().getColumn()).isZero(); + assertThat(origin).isNotNull(); + Resource resource = origin.getResource(); + assertThat(resource).isNotNull(); + assertThat(resource.getFile()).isEqualTo(this.directory.resolve("b").toFile()); + Location location = origin.getLocation(); + assertThat(location).isNotNull(); + assertThat(location.getLine()).isZero(); + assertThat(location.getColumn()).isZero(); } @Test @@ -161,7 +174,9 @@ class ConfigTreePropertySourceTests { environment.getPropertySources().addFirst(getFlatPropertySource()); assertThat(environment.getProperty("a")).isEqualTo("A"); assertThat(environment.getProperty("b")).isEqualTo("B"); - assertThat(environment.getProperty("c", InputStreamSource.class).getInputStream()).hasContent("C"); + InputStreamSource c = environment.getProperty("c", InputStreamSource.class); + assertThat(c).isNotNull(); + assertThat(c.getInputStream()).hasContent("C"); assertThat(environment.getProperty("c", byte[].class)).contains('C'); assertThat(environment.getProperty("one", Integer.class)).isOne(); } @@ -177,6 +192,7 @@ class ConfigTreePropertySourceTests { ConfigTreePropertySource propertySource = getNestedPropertySource(); Value v1 = propertySource.getProperty("fa.b"); Value v2 = propertySource.getProperty("fa.b"); + assertThat(v1).isNotNull(); assertThat(v1).isSameAs(v2); assertThat(v1).hasToString("AB"); assertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('A', 'B'); @@ -192,6 +208,7 @@ class ConfigTreePropertySourceTests { Option.ALWAYS_READ); Value v1 = propertySource.getProperty("fa.b"); Value v2 = propertySource.getProperty("fa.b"); + assertThat(v1).isNotNull(); assertThat(v1).isNotSameAs(v2); assertThat(v1).hasToString("AB"); assertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('A', 'B'); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/env/DefaultPropertiesPropertySourceTests.java b/core/spring-boot/src/test/java/org/springframework/boot/env/DefaultPropertiesPropertySourceTests.java index fad63bd24fb..f905dee6d83 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/env/DefaultPropertiesPropertySourceTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/env/DefaultPropertiesPropertySourceTests.java @@ -44,6 +44,7 @@ import static org.mockito.BDDMockito.then; class DefaultPropertiesPropertySourceTests { @Mock + @SuppressWarnings("NullAway.Init") private Consumer action; @Test @@ -107,7 +108,7 @@ class DefaultPropertiesPropertySourceTests { MutablePropertySources propertySources = environment.getPropertySources(); DefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap("spring", "boot"), propertySources); assertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue(); - assertThat(propertySources.get(DefaultPropertiesPropertySource.NAME).getProperty("spring")).isEqualTo("boot"); + assertThat(getDefaultPropertySource(propertySources).getProperty("spring")).isEqualTo("boot"); } @Test @@ -117,8 +118,8 @@ class DefaultPropertiesPropertySourceTests { propertySources.addLast(new DefaultPropertiesPropertySource(Collections.singletonMap("spring", "boot"))); DefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap("hello", "world"), propertySources); assertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue(); - assertThat(propertySources.get(DefaultPropertiesPropertySource.NAME).getProperty("spring")).isEqualTo("boot"); - assertThat(propertySources.get(DefaultPropertiesPropertySource.NAME).getProperty("hello")).isEqualTo("world"); + assertThat(getDefaultPropertySource(propertySources).getProperty("spring")).isEqualTo("boot"); + assertThat(getDefaultPropertySource(propertySources).getProperty("hello")).isEqualTo("world"); } @Test @@ -130,8 +131,8 @@ class DefaultPropertiesPropertySourceTests { propertySources.addFirst(composite); DefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap("hello", "world"), propertySources); assertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue(); - assertThat(propertySources.get(DefaultPropertiesPropertySource.NAME).getProperty("spring")).isNull(); - assertThat(propertySources.get(DefaultPropertiesPropertySource.NAME).getProperty("hello")).isEqualTo("world"); + assertThat(getDefaultPropertySource(propertySources).getProperty("spring")).isNull(); + assertThat(getDefaultPropertySource(propertySources).getProperty("hello")).isEqualTo("world"); } @Test @@ -146,4 +147,10 @@ class DefaultPropertiesPropertySourceTests { DefaultPropertiesPropertySource.NAME); } + private PropertySource getDefaultPropertySource(MutablePropertySources propertySources) { + PropertySource propertySource = propertySources.get(DefaultPropertiesPropertySource.NAME); + assertThat(propertySource).isNotNull(); + return propertySource; + } + } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java index 9b13527dce6..3c24164eed3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java @@ -20,12 +20,15 @@ import java.io.IOException; import java.util.List; import java.util.Properties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.env.OriginTrackedPropertiesLoader.Document; +import org.springframework.boot.origin.Origin; import org.springframework.boot.origin.OriginTrackedValue; import org.springframework.boot.origin.TextResourceOrigin; +import org.springframework.boot.origin.TextResourceOrigin.Location; import org.springframework.boot.testsupport.classpath.resources.WithResource; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; @@ -375,19 +378,23 @@ class OriginTrackedPropertiesLoaderTests { assertThat(getValue(value)).isEqualTo("abc"); } - private OriginTrackedValue getFromFirst(String key) { + private @Nullable OriginTrackedValue getFromFirst(String key) { return this.documents.get(0).asMap().get(key); } - private Object getValue(OriginTrackedValue value) { + private @Nullable Object getValue(@Nullable OriginTrackedValue value) { return (value != null) ? value.getValue() : null; } - private String getLocation(OriginTrackedValue value) { + private @Nullable String getLocation(@Nullable OriginTrackedValue value) { if (value == null) { return null; } - return ((TextResourceOrigin) value.getOrigin()).getLocation().toString(); + Origin origin = value.getOrigin(); + assertThat(origin).isNotNull(); + Location location = ((TextResourceOrigin) origin).getLocation(); + assertThat(location).isNotNull(); + return location.toString(); } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java index 6597fabaa0b..29e22300794 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java @@ -24,12 +24,14 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.yaml.snakeyaml.composer.ComposerException; import org.springframework.boot.origin.OriginTrackedValue; import org.springframework.boot.origin.TextResourceOrigin; +import org.springframework.boot.origin.TextResourceOrigin.Location; import org.springframework.boot.testsupport.classpath.resources.WithResource; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; @@ -48,7 +50,7 @@ class OriginTrackedYamlLoaderTests { private OriginTrackedYamlLoader loader; - private List> result; + private @Nullable List> result; @BeforeEach void setUp() { @@ -60,6 +62,7 @@ class OriginTrackedYamlLoaderTests { @WithTestYamlResource void processSimpleKey() { OriginTrackedValue value = getValue("name"); + assertThat(value).isNotNull(); assertThat(value).hasToString("Martin D'vloper"); assertThat(getLocation(value)).isEqualTo("3:7"); } @@ -70,10 +73,13 @@ class OriginTrackedYamlLoaderTests { OriginTrackedValue perl = getValue("languages.perl"); OriginTrackedValue python = getValue("languages.python"); OriginTrackedValue pascal = getValue("languages.pascal"); + assertThat(perl).isNotNull(); assertThat(perl).hasToString("Elite"); assertThat(getLocation(perl)).isEqualTo("13:11"); + assertThat(python).isNotNull(); assertThat(python).hasToString("Elite"); assertThat(getLocation(python)).isEqualTo("14:13"); + assertThat(pascal).isNotNull(); assertThat(pascal).hasToString("Lame"); assertThat(getLocation(pascal)).isEqualTo("15:13"); } @@ -85,12 +91,16 @@ class OriginTrackedYamlLoaderTests { OriginTrackedValue orange = getValue("foods[1]"); OriginTrackedValue strawberry = getValue("foods[2]"); OriginTrackedValue mango = getValue("foods[3]"); + assertThat(apple).isNotNull(); assertThat(apple).hasToString("Apple"); assertThat(getLocation(apple)).isEqualTo("8:7"); + assertThat(orange).isNotNull(); assertThat(orange).hasToString("Orange"); assertThat(getLocation(orange)).isEqualTo("9:7"); + assertThat(strawberry).isNotNull(); assertThat(strawberry).hasToString("Strawberry"); assertThat(getLocation(strawberry)).isEqualTo("10:7"); + assertThat(mango).isNotNull(); assertThat(mango).hasToString("Mango"); assertThat(getLocation(mango)).isEqualTo("11:7"); } @@ -99,6 +109,7 @@ class OriginTrackedYamlLoaderTests { @WithTestYamlResource void processMultiline() { OriginTrackedValue education = getValue("education"); + assertThat(education).isNotNull(); assertThat(education).hasToString("4 GCSEs\n3 A-Levels\nBSc in the Internet of Things\n"); assertThat(getLocation(education)).isEqualTo("16:12"); } @@ -110,12 +121,16 @@ class OriginTrackedYamlLoaderTests { OriginTrackedValue url = getValue("example.foo[0].url"); OriginTrackedValue bar1 = getValue("example.foo[0].bar[0].bar1"); OriginTrackedValue bar2 = getValue("example.foo[0].bar[1].bar2"); + assertThat(name).isNotNull(); assertThat(name).hasToString("springboot"); assertThat(getLocation(name)).isEqualTo("22:15"); + assertThat(url).isNotNull(); assertThat(url).hasToString("https://springboot.example.com/"); assertThat(getLocation(url)).isEqualTo("23:14"); + assertThat(bar1).isNotNull(); assertThat(bar1).hasToString("baz"); assertThat(getLocation(bar1)).isEqualTo("25:19"); + assertThat(bar2).isNotNull(); assertThat(bar2).hasToString("bling"); assertThat(getLocation(bar2)).isEqualTo("26:19"); } @@ -126,10 +141,13 @@ class OriginTrackedYamlLoaderTests { OriginTrackedValue empty = getValue("empty"); OriginTrackedValue nullValue = getValue("null-value"); OriginTrackedValue emptyList = getValue("emptylist"); + assertThat(empty).isNotNull(); assertThat(empty.getValue()).isEqualTo(""); assertThat(getLocation(empty)).isEqualTo("27:8"); + assertThat(nullValue).isNotNull(); assertThat(nullValue.getValue()).isEqualTo(""); assertThat(getLocation(nullValue)).isEqualTo("28:13"); + assertThat(emptyList).isNotNull(); assertThat(emptyList.getValue()).isEqualTo(""); assertThat(getLocation(emptyList)).isEqualTo("29:12"); } @@ -231,7 +249,7 @@ class OriginTrackedYamlLoaderTests { } @SuppressWarnings("unchecked") - private T getValue(String name) { + private @Nullable T getValue(String name) { if (this.result == null) { this.result = this.loader.load(); } @@ -239,7 +257,11 @@ class OriginTrackedYamlLoaderTests { } private String getLocation(OriginTrackedValue value) { - return ((TextResourceOrigin) value.getOrigin()).getLocation().toString(); + TextResourceOrigin origin = (TextResourceOrigin) value.getOrigin(); + assertThat(origin).isNotNull(); + Location location = origin.getLocation(); + assertThat(location).isNotNull(); + return location.toString(); } @Retention(RetentionPolicy.RUNTIME) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesTests.java index 5506225f681..b30e54f845a 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.info; import java.util.Properties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.aot.hint.RuntimeHints; @@ -114,7 +115,7 @@ class GitPropertiesTests { assertThat(RuntimeHintsPredicates.resource().forResource("git.properties")).accepts(runtimeHints); } - private static Properties createProperties(String branch, String commitId, String commitIdAbbrev, + private static Properties createProperties(String branch, String commitId, @Nullable String commitIdAbbrev, String commitTime) { Properties properties = new Properties(); properties.put("branch", branch); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java index cd304873d90..62af2226913 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java @@ -207,6 +207,7 @@ class ApplicationResourceLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getWithClassPathAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ClassLoader) null, null)) .withMessage("'springFactoriesLoader' must not be null"); @@ -227,6 +228,7 @@ class ApplicationResourceLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getWithResourceLoaderWhenResourceLoaderIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ResourceLoader) null)) .withMessage("'resourceLoader' must not be null"); @@ -241,6 +243,7 @@ class ApplicationResourceLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getWithResourceLoaderAndSpringFactoriesLoaderWhenResourceLoaderIsNullThrowsException() { SpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader .forResourceLocation(TEST_PROTOCOL_RESOLVERS_FACTORIES); @@ -250,6 +253,7 @@ class ApplicationResourceLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getWithResourceLoaderAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> ApplicationResourceLoader.get(new TestResourceLoader(), null)) @@ -276,6 +280,7 @@ class ApplicationResourceLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getResourceWhenPathIsNull() { ResourceLoader loader = ApplicationResourceLoader.get(); assertThatIllegalArgumentException().isThrownBy(() -> loader.getResource(null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerIntegrationTests.java index f15a0c3b017..cc5dbdf9e96 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerIntegrationTests.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; @@ -62,13 +63,13 @@ class ProtocolResolverApplicationContextInitializerIntegrationTests { @ConfigurationProperties("test") static class TestProperties { - Resource resource; + @Nullable Resource resource; - Resource getResource() { + @Nullable Resource getResource() { return this.resource; } - void setResource(Resource resource) { + void setResource(@Nullable Resource resource) { this.resource = resource; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/io/ReverseStringProtocolResolver.java b/core/spring-boot/src/test/java/org/springframework/boot/io/ReverseStringProtocolResolver.java index f92d6dd82e1..88b292f5583 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/io/ReverseStringProtocolResolver.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/io/ReverseStringProtocolResolver.java @@ -18,6 +18,8 @@ package org.springframework.boot.io; import java.nio.charset.StandardCharsets; +import org.jspecify.annotations.Nullable; + import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ProtocolResolver; import org.springframework.core.io.Resource; @@ -33,7 +35,7 @@ class ReverseStringProtocolResolver implements ProtocolResolver { private static final String PREFIX = "reverse:"; @Override - public Resource resolve(String location, ResourceLoader resourceLoader) { + public @Nullable Resource resolve(String location, ResourceLoader resourceLoader) { if (!location.startsWith(PREFIX)) { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java b/core/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java index 6bb5efbcf2f..c3c3b669825 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java @@ -46,7 +46,9 @@ abstract class AbstractJsonParserTests { Map map = this.parser.parseMap("{\"foo\":\"bar\",\"spam\":1}"); assertThat(map).hasSize(2); assertThat(map).containsEntry("foo", "bar"); - assertThat(((Number) map.get("spam")).longValue()).isOne(); + Object spam = map.get("spam"); + assertThat(spam).isNotNull(); + assertThat(((Number) spam).longValue()).isOne(); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/json/JsonValueWriterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/json/JsonValueWriterTests.java index 10ebb94ce10..8236de659f4 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/json/JsonValueWriterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/json/JsonValueWriterTests.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -296,7 +297,7 @@ class JsonValueWriterTests { "JSON nesting depth (129) exceeds maximum depth of 128 (current path: [0][0][0][0][0][0][0][0][0][0][0][0]"); } - private String write(V value) { + private String write(@Nullable V value) { return doWrite((valueWriter) -> valueWriter.write(value)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java index 1fb0f3e7c52..5c79e2a05ae 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java @@ -24,7 +24,11 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -105,7 +109,8 @@ class JsonWriterTests { @Test void ofAddSupplier() { - JsonWriter writer = JsonWriter.of((members) -> members.add("Spring", () -> "Boot")); + Supplier<@Nullable String> supplier = () -> "Boot"; + JsonWriter writer = JsonWriter.of((members) -> members.add("Spring", supplier)); assertThat(writer.writeToString(PERSON)).isEqualTo(""" {"Spring":"Boot"}"""); } @@ -129,7 +134,8 @@ class JsonWriterTests { @Test void ofFromSupplier() { - JsonWriter writer = JsonWriter.of((members) -> members.from(() -> "Boot")); + Supplier<@Nullable String> supplier = () -> "Boot"; + JsonWriter writer = JsonWriter.of((members) -> members.from(supplier)); assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Boot")); } @@ -223,7 +229,7 @@ class JsonWriterTests { assertThat(write(new int[] { 1, 2, 3 })).isEqualTo("[1,2,3]"); } - private String write(T instance) { + private String write(@Nullable T instance) { return JsonWriter.standard().writeToString(instance); } @@ -245,7 +251,9 @@ class JsonWriterTests { @Test void whenNotNullExtracted() { Person personWithNull = new Person("Spring", null, 10); - JsonWriter writer = JsonWriter.of((members) -> members.add().whenNotNull(Person::lastName)); + Function<@Nullable Person, @Nullable Object> lastName = (person) -> (person != null) ? person.lastName() + : null; + JsonWriter writer = JsonWriter.of((members) -> members.add().whenNotNull(lastName)); assertThat(writer.writeToString(PERSON)).isEqualTo(quoted("Spring Boot (10)")); assertThat(writer.writeToString(personWithNull)).isEmpty(); } @@ -279,7 +287,8 @@ class JsonWriterTests { @Test void whenNot() { - JsonWriter> writer = JsonWriter.of((members) -> members.add().whenNot(List::isEmpty)); + Predicate<@Nullable List> isEmpty = List::isEmpty; + JsonWriter> writer = JsonWriter.of((members) -> members.add().whenNot(isEmpty)); assertThat(writer.writeToString(List.of("a"))).isEqualTo(""" ["a"]"""); assertThat(writer.writeToString(Collections.emptyList())).isEmpty(); @@ -287,7 +296,8 @@ class JsonWriterTests { @Test void when() { - JsonWriter> writer = JsonWriter.of((members) -> members.add().when(List::isEmpty)); + Predicate<@Nullable List> isEmpty = List::isEmpty; + JsonWriter> writer = JsonWriter.of((members) -> members.add().when(isEmpty)); assertThat(writer.writeToString(List.of("a"))).isEmpty(); assertThat(writer.writeToString(Collections.emptyList())).isEqualTo("[]"); } @@ -295,10 +305,10 @@ class JsonWriterTests { @Test void chainedPredicates() { Set banned = Set.of("Spring", "Boot"); - JsonWriter writer = JsonWriter.of((members) -> members.add() - .whenHasLength() - .whenNot(banned::contains) - .whenNot((string) -> string.length() <= 2)); + Predicate<@Nullable String> stringLengthPredicate = (string) -> string != null && string.length() <= 2; + Predicate<@Nullable String> bannedPredicate = (string) -> string != null && banned.contains(string); + JsonWriter writer = JsonWriter + .of((members) -> members.add().whenHasLength().whenNot(bannedPredicate).whenNot(stringLengthPredicate)); assertThat(writer.writeToString("")).isEmpty(); assertThat(writer.writeToString("a")).isEmpty(); assertThat(writer.writeToString("Boot")).isEmpty(); @@ -331,8 +341,9 @@ class JsonWriterTests { @Test void chainedAsAndPredicates() { Extractor booleanExtractor = (integer) -> integer != 0; + Predicate<@Nullable String> isEmpty = (string) -> !StringUtils.hasLength(string); JsonWriter writer = JsonWriter.of((members) -> members.add() - .whenNot(String::isEmpty) + .whenNot(isEmpty) .as(Integer::valueOf) .when((integer) -> integer < 2) .as(booleanExtractor)); @@ -544,7 +555,11 @@ class JsonWriterTests { JsonWriter writer = JsonWriter.of((members) -> { members.add("first", Person::firstName); members.add("last", Person::lastName); - members.applyingPathFilter((path) -> path.name().equals("first")); + members.applyingPathFilter((path) -> { + String name = path.name(); + assertThat(name).isNotNull(); + return name.equals("first"); + }); }); assertThat(writer.writeToString(new Person("spring", "boot", 10))).isEqualTo(""" {"last":"boot"}"""); @@ -554,7 +569,11 @@ class JsonWriterTests { void filteringInMap() { JsonWriter> writer = JsonWriter.of((members) -> { members.add(); - members.applyingPathFilter((path) -> path.name().equals("spring")); + members.applyingPathFilter((path) -> { + String name = path.name(); + assertThat(name).isNotNull(); + return name.equals("spring"); + }); }); assertThat(writer.writeToString(Map.of("spring", "boot", "test", "test"))).isEqualTo(""" @@ -707,11 +726,12 @@ class JsonWriterTests { @Test void of() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase); - assertThat(processor.processValue(null, "test")).isEqualTo("TEST"); + ValueProcessor processor = ValueProcessor.of(stringToUppercase()); + assertThat(processor.processValue(MemberPath.ROOT, "test")).isEqualTo("TEST"); } @Test + @SuppressWarnings("NullAway") // Test null check void ofWhenNull() { assertThatIllegalArgumentException().isThrownBy(() -> ValueProcessor.of(null)) .withMessage("'action' must not be null"); @@ -719,54 +739,54 @@ class JsonWriterTests { @Test void whenHasPathWithStringWhenPathMatches() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase).whenHasPath("foo"); + ValueProcessor processor = ValueProcessor.of(stringToUppercase()).whenHasPath("foo"); assertThat(processor.processValue(MemberPath.ROOT.child("foo"), "test")).isEqualTo("TEST"); } @Test void whenHasPathWithStringWhenPathDoesNotMatch() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase).whenHasPath("foo"); + ValueProcessor processor = ValueProcessor.of(stringToUppercase()).whenHasPath("foo"); assertThat(processor.processValue(MemberPath.ROOT.child("bar"), "test")).isEqualTo("test"); } @Test void whenHasPathWithPredicateWhenPathMatches() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase) + ValueProcessor processor = ValueProcessor.of(stringToUppercase()) .whenHasPath((path) -> path.toString().startsWith("f")); assertThat(processor.processValue(MemberPath.ROOT.child("foo"), "test")).isEqualTo("TEST"); } @Test void whenHasPathWithPredicateWhenPathDoesNotMatch() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase) + ValueProcessor processor = ValueProcessor.of(stringToUppercase()) .whenHasPath((path) -> path.toString().startsWith("f")); assertThat(processor.processValue(MemberPath.ROOT.child("bar"), "test")).isEqualTo("test"); } @Test void whenInstanceOfWhenInstanceMatches() { - ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase(Locale.ROOT)) - .whenInstanceOf(String.class); - assertThat(processor.processValue(null, "test")).hasToString("TEST"); + ValueProcessor processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class); + assertThat(processor.processValue(MemberPath.ROOT, "test")).hasToString("TEST"); } @Test void whenInstanceOfWhenInstanceDoesNotMatch() { - ValueProcessor processor = ValueProcessor.of((value) -> value.toString().toUpperCase(Locale.ROOT)) - .whenInstanceOf(String.class); - assertThat(processor.processValue(null, new StringBuilder("test"))).hasToString("test"); + ValueProcessor processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class); + assertThat(processor.processValue(MemberPath.ROOT, new StringBuilder("test"))).hasToString("test"); } @Test void whenWhenPredicateMatches() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase).when("test"::equals); - assertThat(processor.processValue(null, "test")).isEqualTo("TEST"); + Predicate<@Nullable String> equals = "test"::equals; + ValueProcessor processor = ValueProcessor.of(stringToUppercase()).when(equals); + assertThat(processor.processValue(MemberPath.ROOT, "test")).isEqualTo("TEST"); } @Test void whenWhenPredicateDoesNotMatch() { - ValueProcessor processor = ValueProcessor.of(String::toUpperCase).when("test"::equals); - assertThat(processor.processValue(null, "other")).isEqualTo("other"); + Predicate<@Nullable String> equals = "test"::equals; + ValueProcessor processor = ValueProcessor.of(stringToUppercase()).when(equals); + assertThat(processor.processValue(MemberPath.ROOT, "other")).isEqualTo("other"); } @Test @@ -780,7 +800,7 @@ class JsonWriterTests { JsonWriter writer = JsonWriter.of((members) -> { members.add("first", Person::firstName); members.add("last", Person::lastName); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize)); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize())); }); assertThat(writer.writeToString(new Person("spring", "boot", 10))).isEqualTo(""" {"first":"Spring","last":"Boot"}"""); @@ -790,7 +810,7 @@ class JsonWriterTests { void processValueWhenInMap() { JsonWriter> writer = JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize)); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize())); }); assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo(""" {"spring":"Boot"}"""); @@ -800,7 +820,7 @@ class JsonWriterTests { void processValueWhenInNestedMap() { JsonWriter> writer = JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize)); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize())); }); assertThat(writer.writeToString(Map.of("test", Map.of("spring", "boot")))).isEqualTo(""" {"test":{"spring":"Boot"}}"""); @@ -810,7 +830,7 @@ class JsonWriterTests { void processValueWhenInPairs() { JsonWriter> writer = JsonWriter.of((members) -> { members.add().usingPairs(Map::forEach); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize)); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize())); }); assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo(""" {"spring":"Boot"}"""); @@ -820,7 +840,7 @@ class JsonWriterTests { void processValueWhenCalledWithMultipleTypesIgnoresLambdaErrors() { JsonWriter writer = JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize)); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize())); }); assertThat(writer.writeToString("spring")).isEqualTo("\"Spring\""); assertThat(writer.writeToString(123)).isEqualTo("123"); @@ -831,7 +851,7 @@ class JsonWriterTests { void processValueWhenLimitedToPath() { JsonWriter> writer = JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor(ValueProcessor.of(StringUtils::capitalize).whenHasPath("spring")); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).whenHasPath("spring")); }); assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo(""" {"spring":"Boot"}"""); @@ -843,8 +863,8 @@ class JsonWriterTests { void processValueWhen() { JsonWriter> writer = JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor( - ValueProcessor.of(StringUtils::capitalize).when((candidate) -> candidate.startsWith("b"))); + Predicate<@Nullable String> startsWithB = (candidate) -> candidate != null && candidate.startsWith("b"); + members.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).when(startsWithB)); }); assertThat(writer.writeToString(Map.of("spring", "boot"))).isEqualTo(""" {"spring":"Boot"}"""); @@ -860,7 +880,9 @@ class JsonWriterTests { .usingMembers((personMembers) -> personMembers.add("one", Person::toString)); members.from(Couple::person2) .usingMembers((personMembers) -> personMembers.add("two", Person::toString)); - members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) + ? string.toUpperCase(Locale.ROOT) : null; + members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase)); }); assertThat(writer.writeToString(couple)).isEqualTo(""" {"one":"SPRING BOOT (10)","two":"SPRING FRAMEWORK (20)"}"""); @@ -874,9 +896,12 @@ class JsonWriterTests { .usingMembers((personMembers) -> personMembers.add("one", Person::toString)); members.from(Couple::person2).usingMembers((personMembers) -> { personMembers.add("two", Person::toString); - personMembers.applyingValueProcessor(ValueProcessor.of(String.class, (item) -> item + "!")); + UnaryOperator<@Nullable String> operator = (item) -> item + "!"; + personMembers.applyingValueProcessor(ValueProcessor.of(String.class, operator)); }); - members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) + ? string.toUpperCase(Locale.ROOT) : null; + members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase)); }); assertThat(writer.writeToString(couple)).isEqualTo(""" {"one":"SPRING BOOT (10)","two":"SPRING FRAMEWORK (20)!"}"""); @@ -934,16 +959,30 @@ class JsonWriterTests { assertThat(paths).containsExactly("first", "last"); } + private static UnaryOperator<@Nullable String> stringToUppercase() { + return (string) -> (string != null) ? string.toUpperCase(Locale.ROOT) : null; + } + + private static UnaryOperator<@Nullable Object> objectToUppercase() { + return (string) -> (string != null) ? string.toString().toUpperCase(Locale.ROOT) : null; + } + + private static UnaryOperator<@Nullable String> stringCapitalize() { + return (string) -> (string != null) ? StringUtils.capitalize(string) : null; + } + private JsonWriter simpleWriterWithUppercaseProcessor() { return JsonWriter.of((members) -> { members.add(); - members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) + ? string.toUpperCase(Locale.ROOT) : null; + members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase)); }); } } - record Person(String firstName, String lastName, int age) { + record Person(String firstName, @Nullable String lastName, int age) { @Override public String toString() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/json/WritableJsonTests.java b/core/spring-boot/src/test/java/org/springframework/boot/json/WritableJsonTests.java index 75c12fbe73e..aa3ea133f04 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/json/WritableJsonTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/json/WritableJsonTests.java @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class WritableJsonTests { @TempDir + @SuppressWarnings("NullAway.Init") File temp; @Test @@ -82,6 +83,7 @@ class WritableJsonTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toResourceWithCharsetWhenOutIsNullThrowsException() { WritableJson writable = (out) -> out.append("{}"); assertThatIllegalArgumentException().isThrownBy(() -> writable.toResource(null, StandardCharsets.UTF_8)) @@ -89,6 +91,7 @@ class WritableJsonTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toResourceWithCharsetWhenCharsetIsNullThrowsException() { File file = new File(this.temp, "out.json"); WritableJson writable = (out) -> out.append("{}"); @@ -113,6 +116,7 @@ class WritableJsonTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toOutputStreamWithCharsetWhenOutIsNullThrowsException() { WritableJson writable = (out) -> out.append("{}"); assertThatIllegalArgumentException().isThrownBy(() -> writable.toOutputStream(null, StandardCharsets.UTF_8)) @@ -120,6 +124,7 @@ class WritableJsonTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toOutputStreamWithCharsetWhenCharsetIsNullThrowsException() { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); WritableJson writable = (out) -> out.append("{}"); @@ -136,6 +141,7 @@ class WritableJsonTests { } @Test + @SuppressWarnings("NullAway") // Test null check void toWriterWhenWriterIsNullThrowsException() { WritableJson writable = (out) -> out.append("{}"); assertThatIllegalArgumentException().isThrownBy(() -> writable.toWriter(null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/AbstractLoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/AbstractLoggingSystemTests.java index 412b2b8637b..a0575ebe6b8 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/AbstractLoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/AbstractLoggingSystemTests.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.io.TempDir; @@ -70,11 +71,11 @@ public abstract class AbstractLoggingSystemTests { return system.getSpringConfigLocations(); } - protected final LogFile getLogFile(String file, String path) { + protected final LogFile getLogFile(@Nullable String file, @Nullable String path) { return getLogFile(file, path, true); } - protected final LogFile getLogFile(String file, String path, boolean applyToSystemProperties) { + protected final LogFile getLogFile(@Nullable String file, @Nullable String path, boolean applyToSystemProperties) { LogFile logFile = new LogFile(file, path); if (applyToSystemProperties) { logFile.applyToSystemProperties(); @@ -90,11 +91,11 @@ public abstract class AbstractLoggingSystemTests { return path; } - protected final String getLineWithText(File file, CharSequence outputSearch) { + protected final @Nullable String getLineWithText(File file, CharSequence outputSearch) { return getLineWithText(contentOf(file), outputSearch); } - protected final String getLineWithText(CharSequence output, CharSequence outputSearch) { + protected final @Nullable String getLineWithText(CharSequence output, CharSequence outputSearch) { return Arrays.stream(output.toString().split("\\r?\\n")) .filter((line) -> line.contains(outputSearch)) .findFirst() diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogFactoryTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogFactoryTests.java index d7026fe9747..7ad0a6fe2d3 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogFactoryTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogFactoryTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.logging; import org.apache.commons.logging.Log; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -31,7 +32,7 @@ class DeferredLogFactoryTests { private final DeferredLogFactory factory = (supplier) -> this.log = supplier.get(); - private Log log; + private @Nullable Log log; @Test void getLogFromClassCreatesLogSupplier() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/LogFileTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/LogFileTests.java index f256bcf4d65..95659f70b82 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/LogFileTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/LogFileTests.java @@ -54,6 +54,7 @@ class LogFileTests { private void testLoggingFile(PropertyResolver resolver) { LogFile logFile = LogFile.get(resolver); + assertThat(logFile).isNotNull(); Properties properties = new Properties(); logFile.applyTo(properties); assertThat(logFile).hasToString("log.file"); @@ -70,6 +71,7 @@ class LogFileTests { private void testLoggingPath(PropertyResolver resolver) { LogFile logFile = LogFile.get(resolver); + assertThat(logFile).isNotNull(); Properties properties = new Properties(); logFile.applyTo(properties); assertThat(logFile).hasToString("logpath" + File.separatorChar + "spring.log"); @@ -90,6 +92,7 @@ class LogFileTests { private void testLoggingFileAndPath(PropertyResolver resolver) { LogFile logFile = LogFile.get(resolver); + assertThat(logFile).isNotNull(); Properties properties = new Properties(); logFile.applyTo(properties); assertThat(logFile).hasToString("log.file"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationTests.java index 56c961dda16..2b0260a1490 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationTests.java @@ -34,18 +34,21 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; class LoggerConfigurationTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWithLogLevelWhenNameIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new LoggerConfiguration(null, null, LogLevel.DEBUG)) .withMessage("'name' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWithLogLevelWhenEffectiveLevelIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> new LoggerConfiguration("test", null, (LogLevel) null)) .withMessage("'effectiveLevel' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWithLevelConfigurationWhenNameIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> new LoggerConfiguration(null, null, LevelConfiguration.of(LogLevel.DEBUG))) @@ -53,6 +56,7 @@ class LoggerConfigurationTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createWithLevelConfigurationWhenInheritedLevelConfigurationIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> new LoggerConfiguration("test", null, (LevelConfiguration) null)) @@ -116,6 +120,7 @@ class LoggerConfigurationTests { class LevelConfigurationTests { @Test + @SuppressWarnings("NullAway") // Test null check void ofWhenLogLevelIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> LevelConfiguration.of(null)) .withMessage("'logLevel' must not be null"); @@ -128,6 +133,7 @@ class LoggerConfigurationTests { } @Test + @SuppressWarnings("NullAway") // Test null check void ofCustomWhenNameIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> LevelConfiguration.ofCustom(null)) .withMessage("'name' must not be empty"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerGroupsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerGroupsTests.java index e6909656399..0b5a412394a 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerGroupsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerGroupsTests.java @@ -41,6 +41,7 @@ class LoggerGroupsTests { LoggerGroups loggerGroups = new LoggerGroups(); loggerGroups.putAll(groups); LoggerGroup group = loggerGroups.get("test"); + assertThat(group).isNotNull(); assertThat(group.getMembers()).containsExactly("test.member", "test.member2"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java index b49d6eb5344..cc491eaa349 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.logging; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -84,7 +85,7 @@ class LoggingSystemTests { } @Override - public void setLogLevel(String loggerName, LogLevel level) { + public void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) { // Stub implementation } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/StandardStackTracePrinterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/StandardStackTracePrinterTests.java index 5e0c44bcdb6..3df38bf22da 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/StandardStackTracePrinterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/StandardStackTracePrinterTests.java @@ -208,6 +208,7 @@ class StandardStackTracePrinterTests { } @Test + @SuppressWarnings("NullAway") // Test null check void withFilterWhenPredicateIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> StandardStackTracePrinter.rootFirst().withFilter(null)) .withMessage("'predicate' must not be null"); @@ -267,6 +268,7 @@ class StandardStackTracePrinterTests { } @Test + @SuppressWarnings("NullAway") // Test null check void withFormatterWhenFormatterIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> StandardStackTracePrinter.rootLast().withFormatter(null)) .withMessage("'formatter' must not be null"); @@ -298,6 +300,7 @@ class StandardStackTracePrinterTests { } @Test + @SuppressWarnings("NullAway") // Test null check void withFrameFormatterWhenFormatterIsNullThrowsException() { assertThatIllegalArgumentException() .isThrownBy(() -> StandardStackTracePrinter.rootLast().withFrameFormatter(null)) @@ -336,21 +339,21 @@ class StandardStackTracePrinterTests { .withHashes((frame) -> Objects.hash(frame.getClassName(), frame.getMethodName())); assertThat(printer.printStackTraceToString(exception)).isEqualToNormalizingNewlines(""" <#cc3eebec> java.lang.RuntimeException: exception - at org.springframework.boot.logging.TestException.actualCreateException(TestException.java:63) - at org.springframework.boot.logging.TestException.createException(TestException.java:59) - at org.springframework.boot.logging.TestException.createTestException(TestException.java:49) - at org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:77) + at org.springframework.boot.logging.TestException.actualCreateException(TestException.java:69) + at org.springframework.boot.logging.TestException.createException(TestException.java:65) + at org.springframework.boot.logging.TestException.createTestException(TestException.java:55) + at org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:83) Suppressed: <#834defc3> java.lang.RuntimeException: suppressed - at org.springframework.boot.logging.TestException.createTestException(TestException.java:50) + at org.springframework.boot.logging.TestException.createTestException(TestException.java:56) ... 1 more Caused by: <#611639c5> java.lang.RuntimeException: cause - at org.springframework.boot.logging.TestException.createCause(TestException.java:55) - at org.springframework.boot.logging.TestException.createTestException(TestException.java:48) + at org.springframework.boot.logging.TestException.createCause(TestException.java:61) + at org.springframework.boot.logging.TestException.createTestException(TestException.java:54) ... 1 more Caused by: <#834defc3> java.lang.RuntimeException: root - at org.springframework.boot.logging.TestException.createTestException(TestException.java:47) + at org.springframework.boot.logging.TestException.createTestException(TestException.java:53) ... 1 more - """); + """); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/TestException.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/TestException.java index 68167aeb7a3..8645dc4d1f2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/TestException.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/TestException.java @@ -19,6 +19,10 @@ package org.springframework.boot.logging; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + +import static org.assertj.core.api.Assertions.assertThat; + /** * Creates a test exception without too much stacktrace. * @@ -40,7 +44,9 @@ public final class TestException { catch (InterruptedException ex) { Thread.currentThread().interrupt(); } - return creatorThread.exception; + Exception exception = creatorThread.exception; + assertThat(exception).isNotNull(); + return exception; } private static Exception createTestException() { @@ -70,7 +76,7 @@ public final class TestException { private static final class CreatorThread extends Thread { - Exception exception; + @Nullable Exception exception; @Override public void run() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java index cfcd7acdcdf..08316313496 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java @@ -32,6 +32,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.logging.AbstractLoggingSystemTests; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggerConfiguration; +import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.LoggingSystemProperty; import org.springframework.boot.testsupport.classpath.resources.WithResource; @@ -83,7 +84,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { void noFile(CapturedOutput output) { this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.logger.info("Hello world"); assertThat(output).contains("Hello world").doesNotContain("Hidden"); assertThat(new File(tmpDir() + "/spring.log")).doesNotExist(); @@ -98,7 +99,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { } this.loggingSystem.beforeInitialize(); this.logger.info("Hidden"); - this.loggingSystem.initialize(null, null, getLogFile(null, tmpDir())); + this.loggingSystem.initialize(getInitializationContext(), null, getLogFile(null, tmpDir())); this.logger.info("Hello world"); assertThat(output).contains("Hello world").doesNotContain("Hidden"); assertThat(temp.listFiles(SPRING_LOG_FILTER)).isNotEmpty(); @@ -107,7 +108,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testCustomFormatter(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.logger.info("Hello world"); assertThat(output).contains("Hello world").contains("???? INFO ["); } @@ -116,7 +117,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { void testSystemPropertyInitializesFormat(CapturedOutput output) { System.setProperty(LoggingSystemProperty.PID.getEnvironmentVariableName(), "1234"); this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, + this.loggingSystem.initialize(getInitializationContext(), "classpath:" + ClassUtils.addResourcePathToPackagePath(getClass(), "logging.properties"), null); this.logger.info("Hello world"); this.logger.info("Hello world"); @@ -130,7 +131,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { """) void testNonDefaultConfigLocation(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, "classpath:logging-nondefault.properties", null); + this.loggingSystem.initialize(getInitializationContext(), "classpath:logging-nondefault.properties", null); this.logger.info("Hello world"); assertThat(output).contains("INFO: Hello"); } @@ -138,8 +139,8 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void testNonexistentConfigLocation() { this.loggingSystem.beforeInitialize(); - assertThatIllegalStateException() - .isThrownBy(() -> this.loggingSystem.initialize(null, "classpath:logging-nonexistent.properties", null)); + assertThatIllegalStateException().isThrownBy(() -> this.loggingSystem.initialize(getInitializationContext(), + "classpath:logging-nonexistent.properties", null)); } @Test @@ -151,7 +152,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void setLevel(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.logger.fine("Hello"); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.logger.fine("Hello"); @@ -161,7 +162,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void setLevelToNull(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.logger.fine("Hello"); this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG); this.logger.fine("Hello"); @@ -173,7 +174,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggerConfigurations() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); List configurations = this.loggingSystem.getLoggerConfigurations(); assertThat(configurations).isNotEmpty(); @@ -183,7 +184,7 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void getLoggerConfiguration() { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG); LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName()); assertThat(configuration) @@ -193,9 +194,13 @@ class JavaLoggingSystemTests extends AbstractLoggingSystemTests { @Test void shouldNotContainAnsiEscapeCodes(CapturedOutput output) { this.loggingSystem.beforeInitialize(); - this.loggingSystem.initialize(null, null, null); + this.loggingSystem.initialize(getInitializationContext(), null, null); this.logger.info("Hello world"); assertThat(output).doesNotContain("\033["); } + private LoggingInitializationContext getInitializationContext() { + return new LoggingInitializationContext(null); + } + } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/AbstractStructuredLoggingTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/AbstractStructuredLoggingTests.java index 2e52f2230d3..81d6118e8ed 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/AbstractStructuredLoggingTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/AbstractStructuredLoggingTests.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.impl.MutableLogEvent; import org.apache.logging.log4j.message.SimpleMessage; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -47,6 +48,7 @@ abstract class AbstractStructuredLoggingTests { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Mock + @SuppressWarnings("NullAway.Init") StructuredLoggingJsonMembersCustomizer customizer; MockStructuredLoggingJsonMembersCustomizerBuilder customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>( @@ -65,7 +67,7 @@ abstract class AbstractStructuredLoggingTests { return createEvent(null); } - protected static MutableLogEvent createEvent(Throwable thrown) { + protected static MutableLogEvent createEvent(@Nullable Throwable thrown) { MutableLogEvent event = new MutableLogEvent(); event.setTimeMillis(EVENT_TIME.toEpochMilli()); event.setLevel(Level.INFO); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java index d02e9d0c7bf..a699e7aaef1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.logging.log4j2; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.AbstractLogEvent; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -212,20 +213,22 @@ class ColorConverterTests { assertThat(output).hasToString("\033[32min\033[0;39m"); } - private ColorConverter newConverter(String styling) { - return ColorConverter.newInstance(null, new String[] { this.in, styling }); + private ColorConverter newConverter(@Nullable String styling) { + ColorConverter converter = ColorConverter.newInstance(null, new String[] { this.in, styling }); + assertThat(converter).isNotNull(); + return converter; } static class TestLogEvent extends AbstractLogEvent { - private Level level; + private @Nullable Level level; @Override - public Level getLevel() { + public @Nullable Level getLevel() { return this.level; } - void setLevel(Level level) { + void setLevel(@Nullable Level level) { this.level = level; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatterTests.java index 2db7f407a45..f55917cf875 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatterTests.java @@ -99,6 +99,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL Map expectedError = new HashMap<>(); expectedError.put("type", "java.lang.RuntimeException"); expectedError.put("message", "Boom"); + assertThat(error).isNotNull(); assertThat(error).containsAllEntriesOf(expectedError); String stackTrace = (String) error.get("stack_trace"); assertThat(stackTrace) @@ -120,6 +121,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL event.setThrown(new RuntimeException("Boom")); Map deserialized = deserialize(this.formatter.format(event)); Map error = (Map) deserialized.get("error"); + assertThat(error).isNotNull(); String stackTrace = (String) error.get("stack_trace"); assertThat(stackTrace).isEqualTo("stacktrace:RuntimeException"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverterTests.java index a01792b1fa2..af7dfe183fa 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverterTests.java @@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ class EnclosedInSquareBracketsConverterTests { - private TestLogEvent event; + private final TestLogEvent event = new TestLogEvent(); @Test void transformWhenEmpty() { @@ -46,7 +46,10 @@ class EnclosedInSquareBracketsConverterTests { } private EnclosedInSquareBracketsConverter newConverter(String in) { - return EnclosedInSquareBracketsConverter.newInstance(null, new String[] { in }); + EnclosedInSquareBracketsConverter converter = EnclosedInSquareBracketsConverter.newInstance(null, + new String[] { in }); + assertThat(converter).isNotNull(); + return converter; } } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index 60ff4bd735b..f9e95fdd4f0 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -54,6 +54,7 @@ import org.apache.logging.log4j.jul.Log4jBridgeHandler; import org.apache.logging.log4j.status.StatusListener; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -247,10 +248,11 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { org.apache.logging.log4j.Level level = org.apache.logging.log4j.Level.forName("CUSTOM_LEVEL", 1000); loggerContext.getConfiguration().addLogger(loggerName, new LoggerConfig(loggerName, level, true)); LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(loggerName); + assertThat(configuration).isNotNull(); assertThat(configuration.getLevelConfiguration().getName()).isEqualTo("CUSTOM_LEVEL"); } - private void assertIsPresent(String loggerName, Map loggers, LogLevel logLevel) { + private void assertIsPresent(String loggerName, Map loggers, @Nullable LogLevel logLevel) { assertThat(loggers).containsKey(loggerName); assertThat(loggers).containsEntry(loggerName, logLevel); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2FileXmlTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2FileXmlTests.java index cd382a6e971..1484360904f 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2FileXmlTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2FileXmlTests.java @@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; class Log4j2FileXmlTests extends Log4j2XmlTests { @TempDir + @SuppressWarnings("NullAway.Init") File temp; @Override @@ -94,6 +95,7 @@ class Log4j2FileXmlTests extends Log4j2XmlTests { private String fileAppenderPattern() { prepareConfiguration(); + assertThat(this.configuration).isNotNull(); return ((PatternLayout) this.configuration.getAppender("File").getLayout()).getConversionPattern(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2XmlTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2XmlTests.java index 1efdd549d61..b8734b153ac 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2XmlTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2XmlTests.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.layout.PatternLayout; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -39,11 +40,13 @@ import static org.assertj.core.api.Assertions.assertThat; */ class Log4j2XmlTests { - protected Configuration configuration; + protected @Nullable Configuration configuration; @AfterEach void stopConfiguration() { - this.configuration.stop(); + if (this.configuration != null) { + this.configuration.stop(); + } } @Test @@ -92,6 +95,7 @@ class Log4j2XmlTests { private String consolePattern() { prepareConfiguration(); + assertThat(this.configuration).isNotNull(); return ((PatternLayout) this.configuration.getAppender("Console").getLayout()).getConversionPattern(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java index 1b1b114a3fb..c7a4a8ea5a1 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java @@ -91,7 +91,9 @@ class SpringProfileArbiterTests { private void cleanUpPropertySources() { // https://issues.apache.org/jira/browse/LOG4J2-3618 PropertiesUtil properties = PropertiesUtil.getProperties(); Object environment = ReflectionTestUtils.getField(properties, "environment"); + assertThat(environment).isNotNull(); Set sources = (Set) ReflectionTestUtils.getField(environment, "sources"); + assertThat(sources).isNotNull(); sources.removeIf((candidate) -> candidate instanceof SpringEnvironmentPropertySource || candidate instanceof SpringBootPropertySource); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/StructuredLogLayoutTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/StructuredLogLayoutTests.java index f156218d28e..aff5db7bd9c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/StructuredLogLayoutTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/StructuredLogLayoutTests.java @@ -69,6 +69,7 @@ class StructuredLogLayoutTests extends AbstractStructuredLoggingTests { Map deserialized = deserialize(json); assertThat(deserialized).containsEntry("ecs", Map.of("version", "8.11")); Map error = (Map) deserialized.get("error"); + assertThat(error).isNotNull(); assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java index 9ada125d4d1..c7de85ea630 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java @@ -23,12 +23,13 @@ import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; +import org.jspecify.annotations.Nullable; class TestLog4J2LoggingSystem extends Log4J2LoggingSystem { private final List availableClasses = new ArrayList<>(); - private String[] standardConfigLocations; + private String @Nullable [] standardConfigLocations; TestLog4J2LoggingSystem() { super(TestLog4J2LoggingSystem.class.getClassLoader()); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/AbstractStructuredLoggingTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/AbstractStructuredLoggingTests.java index f6f2cdddb7f..fc806a1b63b 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/AbstractStructuredLoggingTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/AbstractStructuredLoggingTests.java @@ -26,6 +26,7 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.pattern.ThrowableProxyConverter; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; @@ -59,6 +60,7 @@ abstract class AbstractStructuredLoggingTests { private BasicMarkerFactory markerFactory; @Mock + @SuppressWarnings("NullAway.Init") StructuredLoggingJsonMembersCustomizer customizer; MockStructuredLoggingJsonMembersCustomizerBuilder customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>( @@ -106,7 +108,7 @@ abstract class AbstractStructuredLoggingTests { return createEvent(null); } - protected static LoggingEvent createEvent(Throwable thrown) { + protected static LoggingEvent createEvent(@Nullable Throwable thrown) { LoggingEvent event = new LoggingEvent(); event.setInstant(EVENT_TIME); event.setLevel(Level.INFO); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatterTests.java index 7ddb4b5cc47..529e3606d88 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatterTests.java @@ -104,6 +104,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL Map expectedError = new HashMap<>(); expectedError.put("type", "java.lang.RuntimeException"); expectedError.put("message", "Boom"); + assertThat(error).isNotNull(); assertThat(error).containsAllEntriesOf(expectedError); String stackTrace = (String) error.get("stack_trace"); assertThat(stackTrace) @@ -126,6 +127,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL event.setThrowableProxy(new ThrowableProxy(new RuntimeException("Boom"))); Map deserialized = deserialize(this.formatter.format(event)); Map error = (Map) deserialized.get("error"); + assertThat(error).isNotNull(); String stackTrace = (String) error.get("stack_trace"); assertThat(stackTrace).isEqualTo("stacktrace:RuntimeException"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverterTests.java index 90703962225..755e34bcfe2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverterTests.java @@ -22,6 +22,7 @@ import java.util.List; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.LoggerContextVO; import ch.qos.logback.classic.spi.LoggingEvent; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -80,7 +81,7 @@ class EnclosedInSquareBracketsConverterTests { }); } - private void withLoggedApplicationName(String name, String value, Runnable action) { + private void withLoggedApplicationName(String name, @Nullable String value, Runnable action) { if (value == null) { System.clearProperty(name); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java index 89ba0a22329..81b18c77131 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java @@ -59,12 +59,15 @@ import org.springframework.aot.hint.TypeReference; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.logback.SpringBootJoranConfigurator.LogbackConfigurationAotContribution; import org.springframework.context.aot.AbstractAotProcessor; import org.springframework.core.io.InputStreamSource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.Mockito.mock; /** * Tests for {@link LogbackConfigurationAotContribution}. @@ -92,8 +95,10 @@ class LogbackConfigurationAotContributionTests { .map(TypeReference::getName)) .containsExactlyInAnyOrder(namesOf(Model.class, ArrayList.class, Boolean.class, Integer.class)); assertThat(generationContext.getRuntimeHints().reflection().typeHints()).isEmpty(); - Properties patternRules = load( - generatedFiles.getGeneratedFile(Kind.RESOURCE, "META-INF/spring/logback-pattern-rules")); + InputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE, + "META-INF/spring/logback-pattern-rules"); + assertThat(generatedFile).isNotNull(); + Properties patternRules = load(generatedFile); assertThat(patternRules).isEmpty(); } @@ -112,8 +117,10 @@ class LogbackConfigurationAotContributionTests { .map(TypeReference::getName)) .containsExactlyInAnyOrder(namesOf(Model.class, ArrayList.class, Boolean.class, Integer.class)); assertThat(generationContext.getRuntimeHints().reflection().typeHints()).isEmpty(); - Properties patternRules = load( - generatedFiles.getGeneratedFile(Kind.RESOURCE, "META-INF/spring/logback-pattern-rules")); + InputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE, + "META-INF/spring/logback-pattern-rules"); + assertThat(generatedFile).isNotNull(); + Properties patternRules = load(generatedFile); assertThat(patternRules).isEmpty(); } @@ -136,8 +143,10 @@ class LogbackConfigurationAotContributionTests { TestGenerationContext generationContext = applyContribution(new Model()); assertThat(invokePublicConstructorsOf("com.example.Alpha")).accepts(generationContext.getRuntimeHints()); assertThat(invokePublicConstructorsOf("com.example.Bravo")).accepts(generationContext.getRuntimeHints()); - Properties patternRules = load(generationContext.getGeneratedFiles() - .getGeneratedFile(Kind.RESOURCE, "META-INF/spring/logback-pattern-rules")); + InputStreamSource generatedFile = generationContext.getGeneratedFiles() + .getGeneratedFile(Kind.RESOURCE, "META-INF/spring/logback-pattern-rules"); + assertThat(generatedFile).isNotNull(); + Properties patternRules = load(generatedFile); assertThat(patternRules).hasSize(2); assertThat(patternRules).containsEntry("a", "com.example.Alpha"); assertThat(patternRules).containsEntry("b", "com.example.Bravo"); @@ -312,12 +321,13 @@ class LogbackConfigurationAotContributionTests { TestGenerationContext generationContext) { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); contextCustomizer.accept(context); - SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(null); + SpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator( + new LoggingInitializationContext(null)); configurator.setContext(context); withSystemProperty(AbstractAotProcessor.AOT_PROCESSING, "true", () -> configurator.processModel(model)); LogbackConfigurationAotContribution contribution = (LogbackConfigurationAotContribution) context .getObject(BeanFactoryInitializationAotContribution.class.getName()); - contribution.applyTo(generationContext, null); + contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class)); } private String[] namesOf(Class... types) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index 9f251df2e35..6adaeb4d8de 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -51,6 +51,7 @@ import ch.qos.logback.core.status.OnConsoleStatusListener; import ch.qos.logback.core.status.StatusManager; import ch.qos.logback.core.status.WarnStatus; import ch.qos.logback.core.util.DynamicClassLoadingException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -61,6 +62,7 @@ import org.slf4j.MDC; import org.slf4j.bridge.SLF4JBridgeHandler; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.logging.AbstractLoggingSystemTests; import org.springframework.boot.logging.LogFile; @@ -797,7 +799,8 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { @Test void whenContextHasNoAotContributionThenProcessAheadOfTimeReturnsNull() { - BeanFactoryInitializationAotContribution contribution = this.loggingSystem.processAheadOfTime(null); + BeanFactoryInitializationAotContribution contribution = this.loggingSystem + .processAheadOfTime(mock(ConfigurableListableBeanFactory.class)); assertThat(contribution).isNull(); } @@ -806,7 +809,8 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { LoggerContext context = ((LoggerContext) LoggerFactory.getILoggerFactory()); context.putObject(BeanFactoryInitializationAotContribution.class.getName(), mock(BeanFactoryInitializationAotContribution.class)); - BeanFactoryInitializationAotContribution contribution = this.loggingSystem.processAheadOfTime(null); + BeanFactoryInitializationAotContribution contribution = this.loggingSystem + .processAheadOfTime(mock(ConfigurableListableBeanFactory.class)); assertThat(context.getObject(BeanFactoryInitializationAotContribution.class.getName())).isNull(); assertThat(contribution).isNotNull(); } @@ -1139,8 +1143,11 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { assertThat(this.logger.getLoggerContext().getObject(Environment.class.getName())).isSameAs(this.environment); } - private void initialize(LoggingInitializationContext context, String configLocation, LogFile logFile) { - this.loggingSystem.getSystemProperties((ConfigurableEnvironment) context.getEnvironment()).apply(logFile); + private void initialize(LoggingInitializationContext context, @Nullable String configLocation, + @Nullable LogFile logFile) { + ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment(); + assertThat(environment).isNotNull(); + this.loggingSystem.getSystemProperties(environment).apply(logFile); this.loggingSystem.beforeInitialize(); this.loggingSystem.initialize(context, configLocation, logFile); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackRuntimeHintsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackRuntimeHintsTests.java index 36afaedd44f..0c26f69af06 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackRuntimeHintsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackRuntimeHintsTests.java @@ -76,8 +76,10 @@ class LogbackRuntimeHintsTests { private Class loadClass(Resource resource) { try { + String filename = resource.getFilename(); + assertThat(filename).isNotNull(); return getClass().getClassLoader() - .loadClass("org.springframework.boot.logging.logback." + resource.getFilename().replace(".class", "")); + .loadClass("org.springframework.boot.logging.logback." + filename.replace(".class", "")); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); @@ -94,8 +96,7 @@ class LogbackRuntimeHintsTests { private ReflectionHints registerHints() { RuntimeHints hints = new RuntimeHints(); new LogbackRuntimeHints().registerHints(hints, getClass().getClassLoader()); - ReflectionHints reflection = hints.reflection(); - return reflection; + return hints.reflection(); } private Consumer> registeredForPublicConstructorInvocation(ReflectionHints reflection) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java index 986f7bf3e6a..39ec83a2016 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java @@ -82,6 +82,7 @@ class StructuredLogEncoderTests extends AbstractStructuredLoggingTests { Map deserialized = deserialize(json); assertThat(deserialized).containsEntry("ecs", Map.of("version", "8.11")); Map error = (Map) deserialized.get("error"); + assertThat(error).isNotNull(); assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java index 9fe5bbf05a2..865889faf9e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java @@ -17,7 +17,10 @@ package org.springframework.boot.logging.structured; import java.util.List; +import java.util.Locale; +import java.util.function.UnaryOperator; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.json.JsonWriter.Members; @@ -60,9 +63,14 @@ class StructuredLogFormatterFactoryTests { } private void addCommonFormatters(CommonFormatters commonFormatters) { - commonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA, - (instantiator) -> new TestEcsFormatter(instantiator.getArg(Environment.class), - instantiator.getArg(StackTracePrinter.class), instantiator.getArg(StringBuilder.class))); + commonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA, (instantiator) -> { + Environment environment = instantiator.getArg(Environment.class); + assertThat(environment).isNotNull(); + StackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class); + StringBuilder stringBuilder = instantiator.getArg(StringBuilder.class); + assertThat(stringBuilder).isNotNull(); + return new TestEcsFormatter(environment, stackTracePrinter, stringBuilder); + }); } @Test @@ -145,7 +153,9 @@ class StructuredLogFormatterFactoryTests { @Override public void customize(Members members) { - members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) ? string.toUpperCase(Locale.ROOT) + : null; + members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase)); } } @@ -155,7 +165,9 @@ class StructuredLogFormatterFactoryTests { @Override public void customize(Members members) { - members.applyingValueProcessor(ValueProcessor.of(String.class, String::toUpperCase)); + UnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) ? string.toUpperCase(Locale.ROOT) + : null; + members.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase)); } } @@ -172,11 +184,11 @@ class StructuredLogFormatterFactoryTests { private final Environment environment; - private final StackTracePrinter stackTracePrinter; + private final @Nullable StackTracePrinter stackTracePrinter; private final StringBuilder custom; - TestEcsFormatter(Environment environment, StackTracePrinter stackTracePrinter, StringBuilder custom) { + TestEcsFormatter(Environment environment, @Nullable StackTracePrinter stackTracePrinter, StringBuilder custom) { this.environment = environment; this.stackTracePrinter = stackTracePrinter; this.custom = custom; @@ -191,7 +203,7 @@ class StructuredLogFormatterFactoryTests { return this.environment; } - StackTracePrinter getStackTracePrinter() { + @Nullable StackTracePrinter getStackTracePrinter() { return this.stackTracePrinter; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests.java index 7d101ec1874..6650585e86b 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.logging.structured; import java.io.IOException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -29,6 +30,7 @@ import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.factory.aot.AotServices; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; import org.springframework.boot.json.JsonWriter.Members; import org.springframework.boot.logging.StackTracePrinter; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -36,6 +38,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor}. @@ -107,7 +110,7 @@ class StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests assertThat(contribution).isNull(); } - private BeanFactoryInitializationAotContribution getContribution(ConfigurableEnvironment environment) { + private @Nullable BeanFactoryInitializationAotContribution getContribution(ConfigurableEnvironment environment) { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { context.setEnvironment(environment); context.refresh(); @@ -118,7 +121,7 @@ class StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests private RuntimeHints getRuntimeHints(BeanFactoryInitializationAotContribution contribution) { TestGenerationContext generationContext = new TestGenerationContext(); - contribution.applyTo(generationContext, null); + contribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class)); return generationContext.getRuntimeHints(); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizerTests.java index 1441025aef7..4411bac2ee9 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizerTests.java @@ -43,7 +43,7 @@ import static org.mockito.BDDMockito.given; class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests { @Mock - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "NullAway.Init" }) private Instantiator instantiator; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java index dd14560af1f..54bca909f75 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java @@ -67,6 +67,7 @@ class StructuredLoggingJsonPropertiesTests { environment.setProperty("logging.structured.json.stacktrace.include-common-frames", "true"); environment.setProperty("logging.structured.json.stacktrace.include-hashes", "true"); StructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment); + assertThat(properties).isNotNull(); assertThat(properties.stackTrace()) .isEqualTo(new StructuredLoggingJsonProperties.StackTrace("standard", Root.FIRST, 1024, 5, true, true)); } @@ -152,8 +153,9 @@ class StructuredLoggingJsonPropertiesTests { void createPrinterWhenStandardAppliesCustomizations() { Exception exception = TestException.create(); StackTrace properties = new StackTrace(null, Root.FIRST, 300, 2, true, false); - StackTracePrinter printer = ((StandardStackTracePrinter) properties.createPrinter()) - .withLineSeparator("\n"); + StandardStackTracePrinter printer = (StandardStackTracePrinter) properties.createPrinter(); + assertThat(printer).isNotNull(); + printer = printer.withLineSeparator("\n"); String actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception)); assertThat(actual).isEqualToNormalizingNewlines(""" java.lang.RuntimeException: root @@ -168,6 +170,7 @@ class StructuredLoggingJsonPropertiesTests { Exception exception = TestException.create(); StackTrace properties = new StackTrace(null, null, null, null, null, true); StackTracePrinter printer = properties.createPrinter(); + assertThat(printer).isNotNull(); String actual = printer.printStackTraceToString(exception); assertThat(actual).containsPattern("<#[0-9a-z]{8}>"); } @@ -177,6 +180,7 @@ class StructuredLoggingJsonPropertiesTests { Exception exception = TestException.create(); StackTrace properties = new StackTrace(TestStackTracePrinter.class.getName(), null, null, null, true, null); StackTracePrinter printer = properties.createPrinter(); + assertThat(printer).isNotNull(); assertThat(printer.printStackTraceToString(exception)).isEqualTo("java.lang.RuntimeException: exception"); } @@ -186,6 +190,7 @@ class StructuredLoggingJsonPropertiesTests { StackTrace properties = new StackTrace(TestStackTracePrinterCustomized.class.getName(), Root.FIRST, 300, 2, true, null); StackTracePrinter printer = properties.createPrinter(); + assertThat(printer).isNotNull(); String actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception)); assertThat(actual).isEqualTo("RuntimeExceptionroot! at org.springfr..."); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/TestContextPairs.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/TestContextPairs.java index 635a3d0079f..7aa4c029b44 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/TestContextPairs.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/structured/TestContextPairs.java @@ -16,6 +16,8 @@ package org.springframework.boot.logging.structured; +import org.jspecify.annotations.Nullable; + /** * Test access to {@link ContextPairs}. * @@ -30,7 +32,7 @@ public final class TestContextPairs { return of(true, null); } - public static ContextPairs of(boolean include, String prefix) { + public static ContextPairs of(boolean include, @Nullable String prefix) { return new ContextPairs(include, prefix); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/origin/JarUriTests.java b/core/spring-boot/src/test/java/org/springframework/boot/origin/JarUriTests.java index 13400578e32..a5efb7951d5 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/origin/JarUriTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/origin/JarUriTests.java @@ -31,6 +31,7 @@ class JarUriTests { void describeBootInfClassesUri() { JarUri uri = JarUri.from("jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar" + "!/BOOT-INF/classes!/application.properties"); + assertThat(uri).isNotNull(); assertThat(uri.getDescription()).isEqualTo("project-0.0.1-SNAPSHOT.jar"); } @@ -38,6 +39,7 @@ class JarUriTests { void describeBootInfLibUri() { JarUri uri = JarUri.from("jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar" + "!/BOOT-INF/lib/nested.jar!/application.properties"); + assertThat(uri).isNotNull(); assertThat(uri.getDescription()).isEqualTo("project-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/nested.jar"); } @@ -45,12 +47,14 @@ class JarUriTests { void describeRegularJar() { JarUri uri = JarUri .from("jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar!/application.properties"); + assertThat(uri).isNotNull(); assertThat(uri.getDescription()).isEqualTo("project-0.0.1-SNAPSHOT.jar"); } @Test void getDescriptionMergedWithExisting() { JarUri uri = JarUri.from("jar:file:/project-0.0.1-SNAPSHOT.jar!/application.properties"); + assertThat(uri).isNotNull(); assertThat(uri.getDescription("classpath: [application.properties]")) .isEqualTo("classpath: [application.properties] from project-0.0.1-SNAPSHOT.jar"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/origin/MockOrigin.java b/core/spring-boot/src/test/java/org/springframework/boot/origin/MockOrigin.java index 142eaa47208..479a5ea6dc2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/origin/MockOrigin.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/origin/MockOrigin.java @@ -16,6 +16,9 @@ package org.springframework.boot.origin; +import org.jspecify.annotations.Nullable; + +import org.springframework.lang.Contract; import org.springframework.util.Assert; /** @@ -27,16 +30,16 @@ public final class MockOrigin implements Origin { private final String value; - private final Origin parent; + private final @Nullable Origin parent; - private MockOrigin(String value, Origin parent) { + private MockOrigin(String value, @Nullable Origin parent) { Assert.notNull(value, "'value' must not be null"); this.value = value; this.parent = parent; } @Override - public Origin getParent() { + public @Nullable Origin getParent() { return this.parent; } @@ -61,11 +64,13 @@ public final class MockOrigin implements Origin { return this.value; } - public static Origin of(String value) { + @Contract("!null -> !null") + public static @Nullable Origin of(@Nullable String value) { return of(value, null); } - public static Origin of(String value, Origin parent) { + @Contract("!null, _ -> !null") + public static @Nullable Origin of(@Nullable String value, @Nullable Origin parent) { return (value != null) ? new MockOrigin(value, parent) : null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTests.java b/core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTests.java index e03362d96a7..84bbc6c05bd 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.origin; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -93,15 +94,15 @@ class OriginTests { static class TestException extends RuntimeException implements OriginProvider { - private final Origin origin; + private final @Nullable Origin origin; - TestException(Origin origin, Throwable cause) { + TestException(@Nullable Origin origin, @Nullable Throwable cause) { super(cause); this.origin = origin; } @Override - public Origin getOrigin() { + public @Nullable Origin getOrigin() { return this.origin; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/origin/PropertySourceOriginTests.java b/core/spring-boot/src/test/java/org/springframework/boot/origin/PropertySourceOriginTests.java index c4b7c6b9321..cb7fd4bc560 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/origin/PropertySourceOriginTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/origin/PropertySourceOriginTests.java @@ -37,12 +37,14 @@ import static org.mockito.Mockito.withSettings; class PropertySourceOriginTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertySourceIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> new PropertySourceOrigin(null, "name")) .withMessageContaining("'propertySource' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertyNameIsNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> new PropertySourceOrigin(mock(PropertySource.class), null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/origin/SystemEnvironmentOriginTests.java b/core/spring-boot/src/test/java/org/springframework/boot/origin/SystemEnvironmentOriginTests.java index b7c546ea004..a8c90a7ece2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/origin/SystemEnvironmentOriginTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/origin/SystemEnvironmentOriginTests.java @@ -29,13 +29,16 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class SystemEnvironmentOriginTests { @Test + @SuppressWarnings("NullAway") // Test null check void createWhenPropertyIsNullShouldThrowException() { - assertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin(null)); + assertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin(null)) + .withMessage("'property' must not be empty"); } @Test void createWhenPropertyNameIsEmptyShouldThrowException() { - assertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin("")); + assertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin("")) + .withMessage("'property' must not be empty"); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslBundleRegistryTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslBundleRegistryTests.java index e1a50c13956..93b54500e3c 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslBundleRegistryTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslBundleRegistryTests.java @@ -60,12 +60,14 @@ class DefaultSslBundleRegistryTests { } @Test + @SuppressWarnings("NullAway") // Test null check void registerBundleWhenNameIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerBundle(null, this.bundle1)) .withMessage("'name' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void registerBundleWhenBundleIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerBundle("test", null)) .withMessage("'bundle' must not be null"); @@ -85,6 +87,7 @@ class DefaultSslBundleRegistryTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getBundleWhenNameIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> this.registry.getBundle(null)) .withMessage("'name' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslManagerBundleTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslManagerBundleTests.java index 60f7fb481f3..4d2ada89d71 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslManagerBundleTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslManagerBundleTests.java @@ -23,6 +23,7 @@ import java.security.NoSuchAlgorithmException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -38,9 +39,9 @@ import static org.mockito.Mockito.mock; */ class DefaultSslManagerBundleTests { - private KeyManagerFactory keyManagerFactory = mock(KeyManagerFactory.class); + private final KeyManagerFactory keyManagerFactory = mock(KeyManagerFactory.class); - private TrustManagerFactory trustManagerFactory = mock(TrustManagerFactory.class); + private final TrustManagerFactory trustManagerFactory = mock(TrustManagerFactory.class); @Test void getKeyManagerFactoryWhenStoreBundleIsNull() throws Exception { @@ -137,7 +138,7 @@ class DefaultSslManagerBundleTests { */ class TestDefaultSslManagerBundle extends DefaultSslManagerBundle { - TestDefaultSslManagerBundle(SslStoreBundle storeBundle, SslBundleKey key) { + TestDefaultSslManagerBundle(@Nullable SslStoreBundle storeBundle, @Nullable SslBundleKey key) { super(storeBundle, key); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ssl/SslManagerBundleTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ssl/SslManagerBundleTests.java index 61727e6ebcd..c9d7167ee66 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ssl/SslManagerBundleTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ssl/SslManagerBundleTests.java @@ -63,12 +63,14 @@ class SslManagerBundleTests { } @Test + @SuppressWarnings("NullAway") // Test null check void ofWhenKeyManagerFactoryIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> SslManagerBundle.of(null, this.trustManagerFactory)) .withMessage("'keyManagerFactory' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void ofWhenTrustManagerFactoryIsNullThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> SslManagerBundle.of(this.keyManagerFactory, null)) .withMessage("'trustManagerFactory' must not be null"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemContentTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemContentTests.java index c0de1da1d9c..2f79e063f14 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemContentTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemContentTests.java @@ -57,6 +57,7 @@ class PemContentTests { void getCertificateReturnsCertificates() throws Exception { PemContent content = PemContent.load(contentFromClasspath("/test-cert-chain.pem"), ApplicationResourceLoader.get()); + assertThat(content).isNotNull(); List certificates = content.getCertificates(); assertThat(certificates).isNotNull(); assertThat(certificates).hasSize(2); @@ -75,6 +76,7 @@ class PemContentTests { @WithPackageResources("dsa.key") void getPrivateKeyReturnsPrivateKey() throws Exception { PemContent content = PemContent.load(contentFromClasspath("dsa.key"), ApplicationResourceLoader.get()); + assertThat(content).isNotNull(); PrivateKey privateKey = content.getPrivateKey(); assertThat(privateKey).isNotNull(); assertThat(privateKey.getFormat()).isEqualTo("PKCS#8"); @@ -191,7 +193,9 @@ class PemContentTests { @Test @WithPackageResources("test-cert.pem") void loadWithStringWhenClasspathLocationReturnsContent() throws IOException { - String actual = PemContent.load("classpath:test-cert.pem", ApplicationResourceLoader.get()).toString(); + PemContent content = PemContent.load("classpath:test-cert.pem", ApplicationResourceLoader.get()); + assertThat(content).isNotNull(); + String actual = content.toString(); String expected = contentFromClasspath("test-cert.pem"); assertThat(actual).isEqualTo(expected); } @@ -200,7 +204,9 @@ class PemContentTests { @WithPackageResources("test-cert.pem") void loadWithStringWhenFileLocationReturnsContent(@ResourcePath("test-cert.pem") String testCert) throws IOException { - String actual = PemContent.load(testCert, ApplicationResourceLoader.get()).toString(); + PemContent content = PemContent.load(testCert, ApplicationResourceLoader.get()); + assertThat(content).isNotNull(); + String actual = content.toString(); String expected = contentFromClasspath("test-cert.pem"); assertThat(actual).isEqualTo(expected); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreTests.java b/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreTests.java index 951cc004433..b05c1c83241 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreTests.java @@ -51,6 +51,7 @@ class PemSslStoreTests { } @Test + @SuppressWarnings("NullAway") // Test null check void ofWhenNullCertificatesThrowsException() { assertThatIllegalArgumentException().isThrownBy(() -> PemSslStore.of(null, null, null, null, null)) .withMessage("'certificates' must not be empty"); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/support/AnsiOutputApplicationListenerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/support/AnsiOutputApplicationListenerTests.java index aefb127892f..90680e429fb 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/support/AnsiOutputApplicationListenerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/support/AnsiOutputApplicationListenerTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.support; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ class AnsiOutputApplicationListenerTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @BeforeEach void resetAnsi() { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListenerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListenerTests.java index f2a1619b4a3..31b2d41b94d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListenerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListenerTests.java @@ -29,6 +29,7 @@ import java.util.Properties; import java.util.function.Consumer; import java.util.function.Function; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -266,7 +267,8 @@ class EnvironmentPostProcessorApplicationListenerTests { } } - private BeanFactoryInitializationAotContribution getContribution(ConfigurableEnvironment environment) { + private @Nullable BeanFactoryInitializationAotContribution getContribution( + ConfigurableEnvironment environment) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerSingleton(ConfigurableApplicationContext.ENVIRONMENT_BEAN_NAME, environment); return new EnvironmentBeanFactoryInitializationAotProcessor().processAheadOfTime(beanFactory); diff --git a/core/spring-boot/src/test/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessorTests.java index 0c21ebb4bfb..bf31369ab37 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessorTests.java @@ -21,6 +21,7 @@ import java.util.Map; import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringApplication; import org.springframework.boot.json.JsonParseException; import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.core.env.ConfigurableEnvironment; @@ -53,14 +54,14 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json=foo:bar"); assertThatExceptionOfType(JsonParseException.class) - .isThrownBy(() -> this.processor.postProcessEnvironment(this.environment, null)) + .isThrownBy(() -> this.processor.postProcessEnvironment(this.environment, getApplication())) .withMessageContaining("Cannot parse JSON"); } @Test void missing() { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); } @@ -68,7 +69,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { void empty() { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json={}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); } @@ -77,7 +78,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json={\"foo\":\"bar\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo:}")).isEqualTo("bar"); } @@ -86,7 +87,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":\"bar\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo:}")).isEqualTo("bar"); } @@ -95,7 +96,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":{\"bar\":\"spam\",\"rab\":\"maps\"}}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo.bar:}")).isEqualTo("spam"); assertThat(this.environment.resolvePlaceholders("${foo.rab:}")).isEqualTo("maps"); } @@ -105,7 +106,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo.bar\":\"spam\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo.bar:}")).isEqualTo("spam"); } @@ -114,7 +115,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo[1]:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":[\"bar\",\"spam\"]}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo[1]:}")).isEqualTo("spam"); } @@ -123,7 +124,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo[0].bar:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":[{\"bar\":\"spam\"}]}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo[0].bar:}")).isEqualTo("spam"); } @@ -132,8 +133,9 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json={\"foo\":\"bar\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); PropertySource propertySource = this.environment.getPropertySources().get("spring.application.json"); + assertThat(propertySource).isNotNull(); PropertySourceOrigin origin = (PropertySourceOrigin) PropertySourceOrigin.get(propertySource, "foo"); assertThat(origin.getPropertySource().getName()).isEqualTo("Inlined Test Properties"); assertThat(origin.getPropertyName()).isEqualTo("spring.application.json"); @@ -166,7 +168,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { this.environment.getPropertySources().addFirst(custom); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":\"bar\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); PropertySource json = this.environment.getPropertySources().get("spring.application.json"); assertThat(this.environment.getProperty("foo")).isEqualTo("custom"); assertThat(this.environment.getPropertySources()).containsSequence(custom, json, servlet, jndi); @@ -176,7 +178,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { void nullValuesShouldBeAddedToPropertySource() { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":null}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.containsProperty("foo")).isTrue(); } @@ -189,7 +191,7 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { this.environment.getPropertySources().addLast(source); assertThat(this.environment.resolvePlaceholders("${foo}")).isEqualTo("bar"); this.environment.getPropertySources().addLast(source); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.resolvePlaceholders("${foo}")).isEmpty(); } @@ -201,15 +203,19 @@ class SpringApplicationJsonEnvironmentPostProcessorTests { MockPropertySource source = new MockPropertySource(); source.setProperty("foo.baz", "bar"); this.environment.getPropertySources().addLast(source); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.getProperty("foo", Map.class)).isEmpty(); } + private SpringApplication getApplication() { + return new SpringApplication(); + } + private void testServletPropertySource(String servletPropertySourceName) { this.environment.getPropertySources().addFirst(getPropertySource(servletPropertySourceName, "servlet")); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "SPRING_APPLICATION_JSON={\"foo\":\"bar\"}"); - this.processor.postProcessEnvironment(this.environment, null); + this.processor.postProcessEnvironment(this.environment, getApplication()); assertThat(this.environment.getProperty("foo")).isEqualTo("bar"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessorTests.java index d690b2d8e5c..8f9037d6441 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessorTests.java @@ -55,10 +55,12 @@ class SystemEnvironmentPropertySourceEnvironmentPostProcessorTests { void replacedPropertySourceShouldBeOriginAware() { SystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor(); PropertySource original = this.environment.getPropertySources().get("systemEnvironment"); + assertThat(original).isNotNull(); postProcessor.postProcessEnvironment(this.environment, this.application); OriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment .getPropertySources() .get("systemEnvironment"); + assertThat(replaced).isNotNull(); Map originalMap = (Map) original.getSource(); Map replacedMap = replaced.getSource(); originalMap.forEach((key, value) -> { @@ -75,6 +77,7 @@ class SystemEnvironmentPropertySourceEnvironmentPostProcessorTests { OriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment .getPropertySources() .get("systemEnvironment"); + assertThat(replaced).isNotNull(); assertThat(replaced.getOrigin("NON_EXISTENT")).isNull(); } @@ -88,7 +91,9 @@ class SystemEnvironmentPropertySourceEnvironmentPostProcessorTests { OriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment .getPropertySources() .get("systemEnvironment"); + assertThat(replaced).isNotNull(); SystemEnvironmentOrigin origin = (SystemEnvironmentOrigin) replaced.getOrigin("foo.bar.baz"); + assertThat(origin).isNotNull(); assertThat(origin.getProperty()).isEqualTo("FOO_BAR_BAZ"); assertThat(replaced.getProperty("foo.bar.baz")).isEqualTo("hello"); } @@ -102,6 +107,7 @@ class SystemEnvironmentPropertySourceEnvironmentPostProcessorTests { OriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment .getPropertySources() .get("systemEnvironment"); + assertThat(replaced).isNotNull(); assertThat(replaced.getPrefix()).isEqualTo("my"); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java b/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java index 22b034aa492..75b5d10cff0 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java @@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; class ApplicationHomeTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidTests.java b/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidTests.java index b02f6e148a9..3f97831cd62 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidTests.java @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.contentOf; class ApplicationPidTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilderTests.java index 5764d9736da..d5cd29eaac7 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilderTests.java @@ -85,6 +85,7 @@ class SimpleAsyncTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((SimpleAsyncTaskExecutorCustomizer[]) null)) @@ -92,6 +93,7 @@ class SimpleAsyncTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((Set) null)) @@ -134,6 +136,7 @@ class SimpleAsyncTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((SimpleAsyncTaskExecutorCustomizer[]) null)) @@ -141,6 +144,7 @@ class SimpleAsyncTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((Set) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilderTests.java index 1882fef1ad1..639dde9b389 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilderTests.java @@ -76,6 +76,7 @@ class SimpleAsyncTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((SimpleAsyncTaskSchedulerCustomizer[]) null)) @@ -83,6 +84,7 @@ class SimpleAsyncTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((Set) null)) @@ -118,6 +120,7 @@ class SimpleAsyncTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((SimpleAsyncTaskSchedulerCustomizer[]) null)) @@ -125,6 +128,7 @@ class SimpleAsyncTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((Set) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilderTests.java index bbfbe3cc0c3..0094573f346 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilderTests.java @@ -90,6 +90,7 @@ class ThreadPoolTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((ThreadPoolTaskExecutorCustomizer[]) null)) @@ -97,6 +98,7 @@ class ThreadPoolTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((Set) null)) @@ -149,6 +151,7 @@ class ThreadPoolTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((ThreadPoolTaskExecutorCustomizer[]) null)) @@ -156,6 +159,7 @@ class ThreadPoolTaskExecutorBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((Set) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilderTests.java b/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilderTests.java index 35b5bf82a75..fce4b21fa56 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilderTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilderTests.java @@ -73,6 +73,7 @@ class ThreadPoolTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((ThreadPoolTaskSchedulerCustomizer[]) null)) @@ -80,6 +81,7 @@ class ThreadPoolTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void customizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.customizers((Set) null)) @@ -115,6 +117,7 @@ class ThreadPoolTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((ThreadPoolTaskSchedulerCustomizer[]) null)) @@ -122,6 +125,7 @@ class ThreadPoolTaskSchedulerBuilderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { assertThatIllegalArgumentException() .isThrownBy(() -> this.builder.additionalCustomizers((Set) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/util/InstantiatorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/util/InstantiatorTests.java index 7117552c320..307a80a3b35 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/util/InstantiatorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/util/InstantiatorTests.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.util.Instantiator.FailureHandler; @@ -44,7 +45,7 @@ class InstantiatorTests { private final ParamB paramB = new ParamB(); - private ParamC paramC; + private @Nullable ParamC paramC; @Test void instantiateWhenOnlyDefaultConstructorCreatesInstance() { @@ -145,7 +146,9 @@ class InstantiatorTests { } private T createInstance(Class type) { - return createInstantiator(type).instantiate(type.getName()); + T instance = createInstantiator(type).instantiate(type.getName()); + assertThat(instance).isNotNull(); + return instance; } private Instantiator createInstantiator(Class type) { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java b/core/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java index 06e381adef1..3b816fd2790 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java @@ -19,9 +19,12 @@ package org.springframework.boot.util; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.commons.logging.Log; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.util.LambdaSafe.Filter; @@ -44,12 +47,14 @@ import static org.mockito.Mockito.mock; class LambdaSafeTests { @Test + @SuppressWarnings("NullAway") // Test null check void callbackWhenCallbackTypeIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> LambdaSafe.callback(null, new Object(), null)) .withMessageContaining("'callbackType' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void callbackWhenCallbackInstanceIsNullShouldThrowException() { assertThatIllegalArgumentException().isThrownBy(() -> LambdaSafe.callback(Object.class, null, null)) .withMessageContaining("'callbackInstance' must not be null"); @@ -112,83 +117,90 @@ class LambdaSafeTests { NonGenericFactory callbackInstance = mock(NonGenericFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(123); + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(NonGenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result.hasResult()).isTrue(); assertThat(result.get()).isEqualTo(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenHasGenericShouldReturnResult() { StringFactory callbackInstance = mock(StringFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(123); + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result.hasResult()).isTrue(); assertThat(result.get()).isEqualTo(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenReturnNullShouldReturnResult() { StringFactory callbackInstance = mock(StringFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(null); + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result.hasResult()).isTrue(); assertThat(result.get()).isNull(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenHasResolvableGenericMatchShouldReturnResult() { StringBuilderFactory callbackInstance = mock(StringBuilderFactory.class); StringBuilder argument = new StringBuilder("foo"); given(callbackInstance.handle(any(StringBuilder.class))).willReturn(123); + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); then(callbackInstance).should().handle(argument); assertThat(result.hasResult()).isTrue(); assertThat(result.get()).isEqualTo(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult() { GenericFactory callbackInstance = mock(StringBuilderFactory.class); String argument = "foo"; + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result.hasResult()).isFalse(); then(callbackInstance).shouldHaveNoInteractions(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenLambdaMismatchShouldSwallowException() { GenericFactory callbackInstance = (s) -> { fail("Should not get here"); return 123; }; String argument = "foo"; + Function handle = (c) -> c.handle(argument); InvocationResult result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result.hasResult()).isFalse(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbackInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() { GenericMultiArgFactory callbackInstance = (n, s, b) -> { fail("Should not get here"); return 123; }; String argument = "foo"; + Function handle = (c) -> c.handle(1, argument, false); InvocationResult result = LambdaSafe.callback(GenericMultiArgFactory.class, callbackInstance, argument) - .invokeAnd((c) -> c.handle(1, argument, false)); + .invokeAnd(handle); assertThat(result.hasResult()).isFalse(); } @@ -196,57 +208,59 @@ class LambdaSafeTests { void callbacksInvokeWhenNoGenericShouldInvokeCallbacks() { NonGenericCallback callbackInstance = mock(NonGenericCallback.class); String argument = "foo"; + Consumer handle = (c) -> c.handle(argument); LambdaSafe.callbacks(NonGenericCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(argument)); + .invoke(handle); then(callbackInstance).should().handle(argument); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenHasGenericShouldInvokeCallback() { StringCallback callbackInstance = mock(StringCallback.class); String argument = "foo"; - LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(argument)); + Consumer handle = (c) -> c.handle(argument); + LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle); then(callbackInstance).should().handle(argument); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenHasResolvableGenericMatchShouldInvokeCallback() { StringBuilderCallback callbackInstance = mock(StringBuilderCallback.class); StringBuilder argument = new StringBuilder("foo"); - LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(argument)); + Consumer handle = (c) -> c.handle(argument); + LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle); then(callbackInstance).should().handle(argument); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenHasResolvableGenericNonMatchShouldNotInvokeCallback() { GenericCallback callbackInstance = mock(StringBuilderCallback.class); String argument = "foo"; - LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(null)); + Consumer handle = (c) -> c.handle(null); + LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle); then(callbackInstance).shouldHaveNoInteractions(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenLambdaMismatchShouldSwallowException() { GenericCallback callbackInstance = (s) -> fail("Should not get here"); String argument = "foo"; - LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(argument)); + Consumer handle = (c) -> c.handle(argument); + LambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() { GenericMultiArgCallback callbackInstance = (n, s, b) -> fail("Should not get here"); String argument = "foo"; + Consumer handle = (c) -> c.handle(1, argument, false); LambdaSafe.callbacks(GenericMultiArgCallback.class, Collections.singleton(callbackInstance), argument) - .invoke((c) -> c.handle(1, argument, false)); + .invoke(handle); } @Test @@ -254,89 +268,96 @@ class LambdaSafeTests { NonGenericFactory callbackInstance = mock(NonGenericFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(123); + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe .callbacks(NonGenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).containsExactly(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenHasGenericShouldReturnResult() { StringFactory callbackInstance = mock(StringFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(123); + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe .callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).containsExactly(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenReturnNullShouldReturnResult() { StringFactory callbackInstance = mock(StringFactory.class); String argument = "foo"; given(callbackInstance.handle("foo")).willReturn(null); + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe .callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).containsExactly((Integer) null); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenHasResolvableGenericMatchShouldReturnResult() { StringBuilderFactory callbackInstance = mock(StringBuilderFactory.class); StringBuilder argument = new StringBuilder("foo"); given(callbackInstance.handle(any(StringBuilder.class))).willReturn(123); + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe .callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).containsExactly(123); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult() { GenericFactory callbackInstance = mock(StringBuilderFactory.class); String argument = "foo"; + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe .callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).isEmpty(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenLambdaMismatchShouldSwallowException() { GenericFactory callbackInstance = (s) -> { fail("Should not get here"); return 123; }; String argument = "foo"; + Function handle = (c) -> (c).handle(argument); Stream result = LambdaSafe .callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> (c).handle(argument)); + .invokeAnd(handle); assertThat(result).isEmpty(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() { GenericMultiArgFactory callbackInstance = (n, s, b) -> { fail("Should not get here"); return 123; }; String argument = "foo"; + Function handle = (c) -> c.handle(1, argument, false); Stream result = LambdaSafe .callbacks(GenericMultiArgFactory.class, Collections.singleton(callbackInstance), argument) - .invokeAnd((c) -> c.handle(1, argument, false)); + .invokeAnd(handle); assertThat(result).isEmpty(); } @Test - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) void callbacksInvokeWhenMultipleShouldInvokeSuitable() { List> callbackInstances = new ArrayList<>(); GenericFactory callback1 = (s) -> 1; @@ -352,8 +373,9 @@ class LambdaSafeTests { callbackInstances.add(callback4); callbackInstances.add(callback5); String argument = "foo"; + Function handle = (c) -> c.handle(argument); Stream result = LambdaSafe.callbacks(GenericFactory.class, callbackInstances, argument) - .invokeAnd((c) -> c.handle(argument)); + .invokeAnd(handle); assertThat(result).containsExactly(1, 2, 4); } @@ -391,7 +413,7 @@ class LambdaSafeTests { interface GenericCallback { - void handle(T argument); + void handle(@Nullable T argument); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorIntegrationTests.java index f0cacedaa5f..8aadef51c46 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorIntegrationTests.java @@ -42,30 +42,39 @@ import static org.assertj.core.api.Assertions.assertThatException; class MessageSourceMessageInterpolatorIntegrationTests { @NotNull + @SuppressWarnings("NullAway.Init") private String defaultMessage; @NotNull(message = "{null}") + @SuppressWarnings("NullAway.Init") private String nullable; @NotNull(message = "{blank}") + @SuppressWarnings("NullAway.Init") private String blank; @NotNull(message = "{unknown}") + @SuppressWarnings("NullAway.Init") private String unknown; @NotNull(message = "{recursion}") + @SuppressWarnings("NullAway.Init") private String recursion; @NotNull(message = "\\{null}") + @SuppressWarnings("NullAway.Init") private String escapePrefix; @NotNull(message = "{null\\}") + @SuppressWarnings("NullAway.Init") private String escapeSuffix; @NotNull(message = "\\{null\\}") + @SuppressWarnings("NullAway.Init") private String escapePrefixSuffix; @NotNull(message = "\\\\{null}") + @SuppressWarnings("NullAway.Init") private String escapeEscape; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java index 6f984994c46..e6a7fbb997e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java @@ -61,9 +61,11 @@ import static org.mockito.Mockito.never; abstract class AbstractFilterRegistrationBeanTests { @Mock + @SuppressWarnings("NullAway.Init") ServletContext servletContext; @Mock + @SuppressWarnings("NullAway.Init") FilterRegistration.Dynamic registration; @Test @@ -130,6 +132,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void setServletRegistrationBeanMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException().isThrownBy(() -> bean.setServletRegistrationBeans(null)) @@ -137,6 +140,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addServletRegistrationBeanMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException() @@ -164,6 +168,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void setUrlPatternMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException().isThrownBy(() -> bean.setUrlPatterns(null)) @@ -171,6 +176,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addUrlPatternMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException().isThrownBy(() -> bean.addUrlPatterns((String[]) null)) @@ -178,6 +184,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void setServletNameMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException().isThrownBy(() -> bean.setServletNames(null)) @@ -185,6 +192,7 @@ abstract class AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addServletNameMustNotBeNull() { AbstractFilterRegistrationBean bean = createFilterRegistrationBean(); assertThatIllegalArgumentException().isThrownBy(() -> bean.addServletNames((String[]) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBeanTests.java index 7229ae0d0ba..de34891703b 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBeanTests.java @@ -49,12 +49,14 @@ class DelegatingFilterProxyRegistrationBeanTests extends AbstractFilterRegistrat new MockServletContext()); @Test + @SuppressWarnings("NullAway") // Test null check void targetBeanNameMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new DelegatingFilterProxyRegistrationBean(null)) .withMessageContaining("'targetBeanName' must not be empty"); } @Test + @SuppressWarnings("NullAway") // Test null check void targetBeanNameMustNotBeEmpty() { assertThatIllegalArgumentException().isThrownBy(() -> new DelegatingFilterProxyRegistrationBean("")) .withMessageContaining("'targetBeanName' must not be empty"); @@ -86,6 +88,7 @@ class DelegatingFilterProxyRegistrationBeanTests extends AbstractFilterRegistrat } @Test + @SuppressWarnings("NullAway") // Test null check void createServletRegistrationBeanMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy( diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DynamicRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DynamicRegistrationBeanTests.java index 7db36287dc7..b0636685c41 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DynamicRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DynamicRegistrationBeanTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.web.servlet; import jakarta.servlet.Registration.Dynamic; import jakarta.servlet.ServletContext; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -52,13 +53,13 @@ class DynamicRegistrationBeanTests { private static DynamicRegistrationBean createBean() { return new DynamicRegistrationBean<>() { @Override - protected Dynamic addRegistration(String description, ServletContext servletContext) { + protected @Nullable Dynamic addRegistration(String description, ServletContext servletContext) { return null; } @Override protected String getDescription() { - return null; + return ""; } }; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationBeanTests.java index b2d459acb8c..2279577309d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationBeanTests.java @@ -74,12 +74,14 @@ class FilterRegistrationBeanTests extends AbstractFilterRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void constructFilterMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new FilterRegistrationBean<>(null)) .withMessageContaining("'filter' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void createServletRegistrationBeanMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new FilterRegistrationBean<>(this.filter, (ServletRegistrationBean[]) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationIntegrationTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationIntegrationTests.java index b6da2db8252..113794fdb3e 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationIntegrationTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationIntegrationTests.java @@ -22,6 +22,7 @@ import jakarta.servlet.Filter; import jakarta.servlet.FilterRegistration.Dynamic; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -31,6 +32,7 @@ import org.springframework.boot.web.servlet.mock.MockFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; @@ -44,7 +46,7 @@ import static org.mockito.Mockito.times; */ class FilterRegistrationIntegrationTests { - private AnnotationConfigServletWebApplicationContext context; + private @Nullable AnnotationConfigServletWebApplicationContext context; @AfterEach void cleanUp() { @@ -56,6 +58,7 @@ class FilterRegistrationIntegrationTests { @Test void normalFiltersAreRegistered() { load(FilterConfiguration.class); + assertThat(this.context).isNotNull(); then(this.context.getServletContext()).should() .addFilter("myFilter", this.context.getBean("myFilter", MockFilter.class)); } @@ -63,6 +66,7 @@ class FilterRegistrationIntegrationTests { @Test void scopedTargetFiltersAreNotRegistered() { load(ScopedTargetFilterConfiguration.class); + assertThat(this.context).isNotNull(); then(this.context.getServletContext()).should(times(0)).addFilter(any(String.class), any(Filter.class)); } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index 382133f7850..a861ac0217d 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -34,6 +34,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSessionIdListener; import org.assertj.core.api.ThrowingConsumer; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.context.ConfigurableApplicationContext; @@ -56,13 +57,13 @@ import static org.assertj.core.api.Assertions.assertThat; */ class ServletContextInitializerBeansTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @Test void servletThatImplementsServletContextInitializerIsOnlyRegisteredOnce() { load(ServletConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory()); + getContext().getBeanFactory()); assertThat(initializerBeans).hasSize(1); assertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestServlet.class); } @@ -71,7 +72,7 @@ class ServletContextInitializerBeansTests { void filterThatImplementsServletContextInitializerIsOnlyRegisteredOnce() { load(FilterConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory()); + getContext().getBeanFactory()); assertThat(initializerBeans).hasSize(1); assertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestFilter.class); } @@ -80,7 +81,7 @@ class ServletContextInitializerBeansTests { void looksForInitializerBeansOfSpecifiedType() { load(TestConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThat(initializerBeans).hasSize(1); assertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestServletContextInitializer.class); } @@ -89,7 +90,7 @@ class ServletContextInitializerBeansTests { void whenAnHttpSessionIdListenerBeanIsDefinedThenARegistrationBeanIsCreatedForIt() { load(HttpSessionIdListenerConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory()); + getContext().getBeanFactory()); assertThat(initializerBeans).hasSize(1); assertThat(initializerBeans).first() .isInstanceOf(ServletListenerRegistrationBean.class) @@ -101,7 +102,7 @@ class ServletContextInitializerBeansTests { void classesThatImplementMultipleInterfacesAreRegisteredForAllOfThem() { load(MultipleInterfacesConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory()); + getContext().getBeanFactory()); assertThat(initializerBeans).hasSize(3); assertThat(initializerBeans).element(0) .isInstanceOf(ServletRegistrationBean.class) @@ -122,7 +123,7 @@ class ServletContextInitializerBeansTests { void shouldApplyServletRegistrationAnnotation() { load(ServletConfigurationWithAnnotation.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> { assertThat(servletRegistrationBean.isEnabled()).isFalse(); assertThat(servletRegistrationBean.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); @@ -144,7 +145,7 @@ class ServletContextInitializerBeansTests { void shouldApplyFilterRegistrationAnnotation() { load(FilterConfigurationWithAnnotation.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, FilterRegistrationBean.class, (filterRegistrationBean) -> { assertThat(filterRegistrationBean.isEnabled()).isFalse(); assertThat(filterRegistrationBean.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE); @@ -170,7 +171,7 @@ class ServletContextInitializerBeansTests { void shouldApplyFilterRegistrationAnnotationWithDefaultDispatcherTypes() { load(FilterConfigurationWithAnnotationAndDefaultDispatcherTypes.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, FilterRegistrationBean.class, (filterRegistrationBean) -> assertThat(filterRegistrationBean.determineDispatcherTypes()) .containsExactlyElementsOf(EnumSet.allOf(DispatcherType.class))); @@ -180,7 +181,7 @@ class ServletContextInitializerBeansTests { void shouldApplyOrderFromBean() { load(OrderedServletConfiguration.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder()) .isEqualTo(OrderedTestServlet.ORDER)); @@ -190,7 +191,7 @@ class ServletContextInitializerBeansTests { void shouldApplyOrderFromOrderAnnotationOnBeanMethod() { load(ServletConfigurationWithAnnotationAndOrderAnnotation.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder()) .isEqualTo(ServletConfigurationWithAnnotationAndOrderAnnotation.ORDER)); @@ -200,7 +201,7 @@ class ServletContextInitializerBeansTests { void orderedInterfaceShouldTakePrecedenceOverOrderAnnotation() { load(OrderedServletConfigurationWithAnnotationAndOrder.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder()) .isEqualTo(OrderedTestServlet.ORDER)); @@ -210,7 +211,7 @@ class ServletContextInitializerBeansTests { void shouldApplyOrderFromOrderAttribute() { load(ServletConfigurationWithAnnotationAndOrder.class); ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); + getContext().getBeanFactory(), TestServletContextInitializer.class); assertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder()) .isEqualTo(ServletConfigurationWithAnnotationAndOrder.ORDER)); @@ -228,6 +229,11 @@ class ServletContextInitializerBeansTests { code.accept(clazz.cast(initializer)); } + private ConfigurableApplicationContext getContext() { + assertThat(this.context).isNotNull(); + return this.context; + } + @Configuration(proxyBeanMethods = false) static class ServletConfiguration { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBeanTests.java index e36141400fd..f964ec180f6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBeanTests.java @@ -39,9 +39,11 @@ import static org.mockito.Mockito.never; class ServletListenerRegistrationBeanTests { @Mock + @SuppressWarnings("NullAway.Init") private ServletContextListener listener; @Mock + @SuppressWarnings("NullAway.Init") private ServletContext servletContext; @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletRegistrationBeanTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletRegistrationBeanTests.java index b944a7fd0ae..25c84d181e6 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletRegistrationBeanTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletRegistrationBeanTests.java @@ -52,9 +52,11 @@ class ServletRegistrationBeanTests { private final MockServlet servlet = new MockServlet(); @Mock + @SuppressWarnings("NullAway.Init") private ServletContext servletContext; @Mock + @SuppressWarnings("NullAway.Init") private ServletRegistration.Dynamic registration; @Test @@ -140,12 +142,14 @@ class ServletRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createServletMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ServletRegistrationBean(null)) .withMessageContaining("'servlet' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void setMappingMustNotBeNull() { ServletRegistrationBean bean = new ServletRegistrationBean<>(this.servlet); assertThatIllegalArgumentException().isThrownBy(() -> bean.setUrlMappings(null)) @@ -153,6 +157,7 @@ class ServletRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void createMappingMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ServletRegistrationBean<>(this.servlet, (String[]) null)) @@ -160,6 +165,7 @@ class ServletRegistrationBeanTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addMappingMustNotBeNull() { ServletRegistrationBean bean = new ServletRegistrationBean<>(this.servlet); assertThatIllegalArgumentException().isThrownBy(() -> bean.addUrlMappings((String[]) null)) diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/TestServletAndFilterAndListener.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/TestServletAndFilterAndListener.java index d1f43585e1b..cb882aab112 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/TestServletAndFilterAndListener.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/TestServletAndFilterAndListener.java @@ -26,6 +26,7 @@ import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletRequestListener; import jakarta.servlet.ServletResponse; +import org.jspecify.annotations.Nullable; class TestServletAndFilterAndListener implements Servlet, Filter, ServletRequestListener { @@ -41,7 +42,7 @@ class TestServletAndFilterAndListener implements Servlet, Filter, ServletRequest } @Override - public ServletConfig getServletConfig() { + public @Nullable ServletConfig getServletConfig() { return null; } @@ -52,7 +53,7 @@ class TestServletAndFilterAndListener implements Servlet, Filter, ServletRequest } @Override - public String getServletInfo() { + public @Nullable String getServletInfo() { return null; } diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterTests.java index 05af53e67a3..f30f4f56b43 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterTests.java @@ -76,7 +76,7 @@ class ErrorPageFilterTests { void notAnError() throws Exception { this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat(getChainResponse().getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); assertThat(this.response.getForwardedUrl()).isNull(); } @@ -89,9 +89,8 @@ class ErrorPageFilterTests { response.flushBuffer(); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponse) this.chain.getResponse()).getStatus()).isEqualTo(201); - assertThat(((HttpServletResponse) ((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()) - .getStatus()).isEqualTo(201); + assertThat(getChainResponse().getStatus()).isEqualTo(201); + assertThat(((HttpServletResponse) getChainResponse().getResponse()).getStatus()).isEqualTo(201); assertThat(this.response.isCommitted()).isTrue(); } @@ -101,7 +100,7 @@ class ErrorPageFilterTests { this.chain = new TestFilterChain((request, response, chain) -> response.sendError(401, "UNAUTHORIZED")); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - HttpServletResponseWrapper wrapper = (HttpServletResponseWrapper) this.chain.getResponse(); + HttpServletResponseWrapper wrapper = getChainResponse(); assertThat(wrapper.getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); assertThat(wrapper.getStatus()).isEqualTo(401); @@ -117,8 +116,8 @@ class ErrorPageFilterTests { this.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, "BAD")); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(400); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getStatus()).isEqualTo(400); assertThat(this.response.getForwardedUrl()).isNull(); assertThat(this.response.isCommitted()).isTrue(); } @@ -141,8 +140,8 @@ class ErrorPageFilterTests { this.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, "BAD")); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(400); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getStatus()).isEqualTo(400); assertThat(this.response.getForwardedUrl()).isNull(); assertThat(this.response.isCommitted()).isTrue(); } @@ -162,7 +161,7 @@ class ErrorPageFilterTests { this.filter.addErrorPages(new ErrorPage("/error")); this.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, "BAD")); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(400); + assertThat((getChainResponse()).getStatus()).isEqualTo(400); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(400); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo("BAD"); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo("/test/path"); @@ -175,7 +174,7 @@ class ErrorPageFilterTests { this.filter.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400")); this.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, "BAD")); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(400); + assertThat((getChainResponse()).getStatus()).isEqualTo(400); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(400); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo("BAD"); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo("/test/path"); @@ -191,7 +190,7 @@ class ErrorPageFilterTests { response.flushBuffer(); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(400); + assertThat((getChainResponse()).getStatus()).isEqualTo(400); assertThat(this.response.isCommitted()).isTrue(); assertThat(this.response.getForwardedUrl()).isNull(); } @@ -204,7 +203,7 @@ class ErrorPageFilterTests { throw new RuntimeException("BAD"); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(500); + assertThat((getChainResponse()).getStatus()).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo("BAD"); Map requestAttributes = getAttributesForDispatch("/500"); @@ -233,7 +232,7 @@ class ErrorPageFilterTests { void statusCode() throws Exception { this.chain = new TestFilterChain((request, response, chain) -> assertThat(response.getStatus()).isEqualTo(200)); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(200); + assertThat((getChainResponse()).getStatus()).isEqualTo(200); } @Test @@ -244,7 +243,7 @@ class ErrorPageFilterTests { throw new IllegalStateException("BAD"); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(500); + assertThat((getChainResponse()).getStatus()).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo("BAD"); Map requestAttributes = getAttributesForDispatch("/500"); @@ -262,7 +261,7 @@ class ErrorPageFilterTests { this.request.setAsyncStarted(true); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isFalse(); } @@ -276,7 +275,7 @@ class ErrorPageFilterTests { }); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); } @@ -290,7 +289,7 @@ class ErrorPageFilterTests { }); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); } @@ -299,7 +298,7 @@ class ErrorPageFilterTests { setUpAsyncDispatch(); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isFalse(); } @@ -313,7 +312,7 @@ class ErrorPageFilterTests { }); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); } @@ -327,7 +326,7 @@ class ErrorPageFilterTests { }); this.filter.doFilter(this.request, this.response, this.chain); assertThat(this.chain.getRequest()).isEqualTo(this.request); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getResponse()).isEqualTo(this.response); + assertThat((getChainResponse()).getResponse()).isEqualTo(this.response); assertThat(this.response.isCommitted()).isTrue(); } @@ -373,7 +372,7 @@ class ErrorPageFilterTests { throw new ServletException("Wrapper", new RuntimeException("BAD")); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(500); + assertThat((getChainResponse()).getStatus()).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo("BAD"); Map requestAttributes = getAttributesForDispatch("/500"); @@ -394,7 +393,7 @@ class ErrorPageFilterTests { throw new MissingServletRequestParameterException("test", "string"); }); this.filter.doFilter(this.request, this.response, this.chain); - assertThat(((HttpServletResponseWrapper) this.chain.getResponse()).getStatus()).isEqualTo(500); + assertThat((getChainResponse()).getStatus()).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500); assertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)) .isEqualTo("Required request parameter 'test' for method parameter type string is not present"); @@ -433,6 +432,12 @@ class ErrorPageFilterTests { return this.request.getDispatcher(path).getRequestAttributes(); } + private HttpServletResponseWrapper getChainResponse() { + HttpServletResponseWrapper response = (HttpServletResponseWrapper) this.chain.getResponse(); + assertThat(response).isNotNull(); + return response; + } + static class TestFilterChain extends MockFilterChain { private final FilterHandler handler; @@ -486,7 +491,9 @@ class ErrorPageFilterTests { } private AttributeCapturingRequestDispatcher getDispatcher(String path) { - return this.dispatchers.get(path); + AttributeCapturingRequestDispatcher dispatcher = this.dispatchers.get(path); + assertThat(dispatcher).isNotNull(); + return dispatcher; } private static final class AttributeCapturingRequestDispatcher extends MockRequestDispatcher { diff --git a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializerTests.java b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializerTests.java index 50f2c6e1b68..e0ebb7f6164 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializerTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializerTests.java @@ -29,6 +29,7 @@ import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextListener; import jakarta.servlet.ServletException; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -70,7 +71,7 @@ class SpringBootServletInitializerTests { private final ServletContext servletContext = new MockServletContext(); - private SpringApplication application; + private @Nullable SpringApplication application; @AfterEach void verifyLoggingOutput(CapturedOutput output) { @@ -87,6 +88,7 @@ class SpringBootServletInitializerTests { @Test void withConfigurationAnnotation() { new WithConfigurationAnnotation().createRootApplicationContext(this.servletContext); + assertThat(this.application).isNotNull(); assertThat(this.application.getAllSources()).containsOnly(WithConfigurationAnnotation.class, ErrorPageFilterConfiguration.class); } @@ -94,6 +96,7 @@ class SpringBootServletInitializerTests { @Test void withConfiguredSource() { new WithConfiguredSource().createRootApplicationContext(this.servletContext); + assertThat(this.application).isNotNull(); assertThat(this.application.getAllSources()).containsOnly(Config.class, ErrorPageFilterConfiguration.class); } @@ -116,6 +119,7 @@ class SpringBootServletInitializerTests { new WithConfigurationAnnotation().onStartup(this.servletContext); assertThat(this.servletContext.getAttribute(LoggingApplicationListener.REGISTER_SHUTDOWN_HOOK_PROPERTY)) .isEqualTo(false); + assertThat(this.application).isNotNull(); Object properties = ReflectionTestUtils.getField(this.application, "properties"); assertThat(properties).hasFieldOrPropertyWithValue("registerShutdownHook", false); } @@ -124,6 +128,7 @@ class SpringBootServletInitializerTests { void errorPageFilterRegistrationCanBeDisabled() { try (AbstractApplicationContext context = (AbstractApplicationContext) new WithErrorPageFilterNotRegistered() .createRootApplicationContext(this.servletContext)) { + assertThat(context).isNotNull(); Map errorPageFilterBeans = context.getBeansOfType(ErrorPageFilter.class); assertThat(errorPageFilterBeans).isEmpty(); } @@ -138,9 +143,11 @@ class SpringBootServletInitializerTests { given(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration()); try (AbstractApplicationContext context = (AbstractApplicationContext) new WithErrorPageFilter() .createRootApplicationContext(servletContext)) { + assertThat(context).isNotNull(); Map registrations = context.getBeansOfType(FilterRegistrationBean.class); assertThat(registrations).hasSize(1); FilterRegistrationBean errorPageFilterRegistration = registrations.get("errorPageFilterRegistration"); + assertThat(errorPageFilterRegistration).isNotNull(); assertThat(errorPageFilterRegistration.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE + 1); } } @@ -154,6 +161,7 @@ class SpringBootServletInitializerTests { given(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration()); try (AbstractApplicationContext context = (AbstractApplicationContext) new WithErrorPageFilter() .createRootApplicationContext(servletContext)) { + assertThat(context).isNotNull(); Map registrations = context.getBeansOfType(FilterRegistrationBean.class); assertThat(registrations).hasSize(1); FilterRegistrationBean errorPageFilterRegistration = registrations.get("errorPageFilterRegistration"); @@ -179,6 +187,7 @@ class SpringBootServletInitializerTests { given(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration()); try (ConfigurableApplicationContext context = (ConfigurableApplicationContext) new PropertySourceVerifyingSpringBootServletInitializer() .createRootApplicationContext(servletContext)) { + assertThat(context).isNotNull(); assertThat(context.getEnvironment().getActiveProfiles()).containsExactly("from-servlet-context"); } } @@ -252,7 +261,7 @@ class SpringBootServletInitializerTests { private class MockSpringBootServletInitializer extends SpringBootServletInitializer { @Override - protected WebApplicationContext run(SpringApplication application) { + protected @Nullable WebApplicationContext run(SpringApplication application) { SpringBootServletInitializerTests.this.application = application; return null; } @@ -333,6 +342,7 @@ class SpringBootServletInitializerTests { PropertySource propertySource = event.getEnvironment() .getPropertySources() .get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME); + assertThat(propertySource).isNotNull(); assertThat(propertySource.getProperty("spring.profiles.active")).isEqualTo("from-servlet-context"); }