From e878db0abf582defc517c8eff7a57e491cfb4743 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Fri, 19 Sep 2025 14:39:47 +0200 Subject: [PATCH] Add nullability annotations to tests in module/spring-boot-devtools See gh-47263 --- module/spring-boot-devtools/build.gradle | 9 ++++++ ...ToolsDataSourceAutoConfigurationTests.java | 11 +++++-- .../DevToolsR2dbcAutoConfigurationTests.java | 7 ++-- .../LocalDevToolsAutoConfigurationTests.java | 24 ++++++++++---- .../RemoteDevToolsAutoConfigurationTests.java | 20 ++++++++---- .../autoconfigure/TriggerFileFilterTests.java | 2 ++ .../classpath/ClassPathChangedEventTests.java | 1 + .../ClassPathFileChangeListenerTests.java | 5 +++ .../ClassPathFileSystemWatcherTests.java | 2 ++ .../PatternClassPathRestartStrategyTests.java | 3 +- .../DevToolPropertiesIntegrationTests.java | 13 +++++--- ...ToolsHomePropertiesPostProcessorTests.java | 8 +++-- .../devtools/filewatch/ChangedFileTests.java | 4 +++ .../filewatch/DirectorySnapshotTests.java | 5 ++- .../devtools/filewatch/FileSnapshotTests.java | 2 ++ .../filewatch/FileSystemWatcherTests.java | 32 +++++++++++-------- .../boot/devtools/livereload/FrameTests.java | 2 ++ .../livereload/LiveReloadServerTests.java | 20 ++++++++---- .../client/ClassPathChangeUploaderTests.java | 5 ++- .../client/DelayedLiveReloadTriggerTests.java | 9 ++++++ .../client/HttpHeaderInterceptorTests.java | 4 +++ .../RemoteClientConfigurationTests.java | 21 +++++++++--- .../remote/server/DispatcherFilterTests.java | 3 ++ .../remote/server/DispatcherTests.java | 3 ++ .../server/HttpHeaderAccessManagerTests.java | 2 ++ .../remote/server/HttpStatusHandlerTests.java | 1 + .../remote/server/UrlHandlerMapperTests.java | 1 + .../devtools/restart/ChangeableUrlsTests.java | 1 + .../devtools/restart/MainMethodTests.java | 10 ++++-- .../restart/RestartScopeInitializerTests.java | 7 ++-- .../boot/devtools/restart/RestarterTests.java | 11 +++++-- .../SilentExitExceptionHandlerTests.java | 9 ++++-- .../classloader/ClassLoaderFileTests.java | 4 +++ .../classloader/ClassLoaderFilesTests.java | 3 ++ .../classloader/RestartClassLoaderTests.java | 3 ++ .../server/HttpRestartServerHandlerTests.java | 1 + .../server/HttpRestartServerTests.java | 3 ++ .../restart/server/RestartServerTests.java | 6 ++-- 38 files changed, 213 insertions(+), 64 deletions(-) diff --git a/module/spring-boot-devtools/build.gradle b/module/spring-boot-devtools/build.gradle index 3a707dfd978..12544996635 100644 --- a/module/spring-boot-devtools/build.gradle +++ b/module/spring-boot-devtools/build.gradle @@ -118,3 +118,12 @@ tasks.register("syncIntTestDependencies", Sync) { intTest { dependsOn syncIntTestDependencies } + +tasks.named("compileTestJava") { + options.nullability.checking = "tests" +} + +tasks.named("compileIntTestJava") { + options.nullability.checking = "tests" +} + diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java index 8831afd661e..8f85128a2b0 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java @@ -25,6 +25,7 @@ import java.util.function.Supplier; import javax.sql.DataSource; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; @@ -35,6 +36,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; import static org.mockito.BDDMockito.willReturn; @@ -99,18 +101,21 @@ abstract class AbstractDevToolsDataSourceAutoConfigurationTests { }); thread.start(); thread.join(); - return atomicReference.get(); + ConfigurableApplicationContext context = atomicReference.get(); + assertThat(context).isNotNull(); + return context; } protected final ConfigurableApplicationContext createContext(Class... classes) { return createContext(null, classes); } - protected final ConfigurableApplicationContext createContext(String driverClassName, Class... classes) { + protected final ConfigurableApplicationContext createContext(@Nullable String driverClassName, + Class... classes) { return createContext(driverClassName, null, classes); } - protected final ConfigurableApplicationContext createContext(String driverClassName, String url, + protected final ConfigurableApplicationContext createContext(@Nullable String driverClassName, @Nullable String url, Class... classes) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(classes); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java index 02426cfb9b4..61c0983f006 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import io.r2dbc.spi.ConnectionFactory; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -125,14 +126,16 @@ class DevToolsR2dbcAutoConfigurationTests { }); thread.start(); thread.join(); - return atomicReference.get(); + ConfigurableApplicationContext context = atomicReference.get(); + assertThat(context).isNotNull(); + return context; } protected final ConfigurableApplicationContext createContext(Class... classes) { return createContext(null, classes); } - protected final ConfigurableApplicationContext createContext(String url, Class... classes) { + protected final ConfigurableApplicationContext createContext(@Nullable String url, Class... classes) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); if (!ObjectUtils.isEmpty(classes)) { context.register(classes); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index f0dafa7edf3..454e7a4e00d 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -26,6 +26,7 @@ import java.util.function.Supplier; import org.apache.catalina.Container; import org.apache.catalina.core.StandardWrapper; import org.apache.jasper.EmbeddedServletOptions; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -74,7 +75,7 @@ import static org.mockito.Mockito.reset; @ExtendWith(MockRestarter.class) class LocalDevToolsAutoConfigurationTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @AfterEach void cleanup() { @@ -152,8 +153,10 @@ class LocalDevToolsAutoConfigurationTests { Map properties = new HashMap<>(); properties.put("spring.devtools.livereload.enabled", false); this.context = getContext(() -> initializeAndRun(Config.class, properties)); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(OptionalLiveReloadServer.class)); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(OptionalLiveReloadServer.class); + }); } @Test @@ -184,8 +187,10 @@ class LocalDevToolsAutoConfigurationTests { Map properties = new HashMap<>(); properties.put("spring.devtools.restart.enabled", false); this.context = getContext(() -> initializeAndRun(Config.class, properties)); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(ClassPathFileSystemWatcher.class)); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(ClassPathFileSystemWatcher.class); + }); } @Test @@ -195,7 +200,9 @@ class LocalDevToolsAutoConfigurationTests { this.context = getContext(() -> initializeAndRun(Config.class, properties)); ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class); Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher"); + assertThat(watcher).isNotNull(); Object filter = ReflectionTestUtils.getField(watcher, "triggerFilter"); + assertThat(filter).isNotNull(); assertThat(filter).isInstanceOf(TriggerFileFilter.class); } @@ -206,6 +213,7 @@ class LocalDevToolsAutoConfigurationTests { this.context = getContext(() -> initializeAndRun(Config.class, properties)); ClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class); Object watcher = ReflectionTestUtils.getField(classPathWatcher, "fileSystemWatcher"); + assertThat(watcher).isNotNull(); @SuppressWarnings("unchecked") Map directories = (Map) ReflectionTestUtils.getField(watcher, "directories"); assertThat(directories).hasSize(2) @@ -218,10 +226,12 @@ class LocalDevToolsAutoConfigurationTests { this.context = getContext(() -> initializeAndRun(Config.class)); TomcatWebServer tomcatContainer = (TomcatWebServer) ((ServletWebServerApplicationContext) this.context) .getWebServer(); + assertThat(tomcatContainer).isNotNull(); Container context = tomcatContainer.getTomcat().getHost().findChildren()[0]; StandardWrapper jspServletWrapper = (StandardWrapper) context.findChild("jsp"); EmbeddedServletOptions options = (EmbeddedServletOptions) ReflectionTestUtils .getField(jspServletWrapper.getServlet(), "options"); + assertThat(options).isNotNull(); assertThat(options.getDevelopment()).isTrue(); } @@ -234,7 +244,9 @@ class LocalDevToolsAutoConfigurationTests { }); thread.start(); thread.join(); - return atomicReference.get(); + ConfigurableApplicationContext context = atomicReference.get(); + assertThat(context).isNotNull(); + return context; } private ConfigurableApplicationContext initializeAndRun(Class config, String... args) { diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java index 7357882a399..01c1b492a07 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java @@ -20,6 +20,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import jakarta.servlet.Filter; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -65,7 +66,7 @@ class RemoteDevToolsAutoConfigurationTests { private static final String DEFAULT_SECRET_HEADER_NAME = RemoteDevToolsProperties.DEFAULT_SECRET_HEADER_NAME; - private AnnotationConfigServletWebApplicationContext context; + private @Nullable AnnotationConfigServletWebApplicationContext context; private MockHttpServletRequest request; @@ -90,8 +91,10 @@ class RemoteDevToolsAutoConfigurationTests { @Test void disabledIfRemoteSecretIsMissing() throws Exception { this.context = getContext(() -> loadContext("a:b")); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(DispatcherFilter.class)); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(DispatcherFilter.class); + }); } @Test @@ -182,8 +185,10 @@ class RemoteDevToolsAutoConfigurationTests { void disableRestart() throws Exception { this.context = getContext(() -> loadContext("spring.devtools.remote.secret:supersecret", "spring.devtools.remote.restart.enabled:false")); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean("remoteRestartHandlerMapper")); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean("remoteRestartHandlerMapper"); + }); } @Test @@ -218,10 +223,13 @@ class RemoteDevToolsAutoConfigurationTests { }); thread.start(); thread.join(); - return atomicReference.get(); + AnnotationConfigServletWebApplicationContext context = atomicReference.get(); + assertThat(context).isNotNull(); + return context; } private void assertRestartInvoked(boolean value) { + assertThat(this.context).isNotNull(); assertThat(this.context.getBean(MockHttpRestartServer.class).invoked).isEqualTo(value); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java index e3ab8addfce..902dd12fb1b 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java @@ -32,9 +32,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class TriggerFileFilterTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test + @SuppressWarnings("NullAway") // Test null check void nameMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new TriggerFileFilter(null)) .withMessageContaining("'name' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathChangedEventTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathChangedEventTests.java index 96180cfb2de..3e83b2ee431 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathChangedEventTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathChangedEventTests.java @@ -36,6 +36,7 @@ class ClassPathChangedEventTests { private final Object source = new Object(); @Test + @SuppressWarnings("NullAway") // Test null check void changeSetMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangedEvent(this.source, null, false)) .withMessageContaining("'changeSet' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListenerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListenerTests.java index 01284feda02..0627ccc0f22 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListenerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListenerTests.java @@ -47,15 +47,19 @@ import static org.mockito.Mockito.never; class ClassPathFileChangeListenerTests { @Mock + @SuppressWarnings("NullAway.Init") private ApplicationEventPublisher eventPublisher; @Mock + @SuppressWarnings("NullAway.Init") private ClassPathRestartStrategy restartStrategy; @Mock + @SuppressWarnings("NullAway.Init") private FileSystemWatcher fileSystemWatcher; @Test + @SuppressWarnings("NullAway") // Test null check void eventPublisherMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ClassPathFileChangeListener(null, this.restartStrategy, this.fileSystemWatcher)) @@ -63,6 +67,7 @@ class ClassPathFileChangeListenerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void restartStrategyMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ClassPathFileChangeListener(this.eventPublisher, null, this.fileSystemWatcher)) diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcherTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcherTests.java index be471c29dc8..dfd3fd9310f 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcherTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcherTests.java @@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock; class ClassPathFileSystemWatcherTests { @Test + @SuppressWarnings("NullAway") // Test null check void urlsMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ClassPathFileSystemWatcher(mock(FileSystemWatcherFactory.class), @@ -100,6 +101,7 @@ class ClassPathFileSystemWatcherTests { ClassPathFileSystemWatcher watcher(ClassPathRestartStrategy restartStrategy) { FileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(100), Duration.ofMillis(10)); URL[] urls = this.environment.getProperty("urls", URL[].class); + assertThat(urls).isNotNull(); return new ClassPathFileSystemWatcher(new MockFileSystemWatcherFactory(watcher), restartStrategy, urls); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategyTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategyTests.java index 9eea957eab4..17d91ff00c8 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategyTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategyTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.devtools.classpath; import java.io.File; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.devtools.filewatch.ChangedFile; @@ -82,7 +83,7 @@ class PatternClassPathRestartStrategyTests { assertRestartRequired(strategy, "com/example/Example.class", true); } - private ClassPathRestartStrategy createStrategy(String pattern) { + private ClassPathRestartStrategy createStrategy(@Nullable String pattern) { return new PatternClassPathRestartStrategy(pattern); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java index 05f9e180623..70bce31c058 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ class DevToolPropertiesIntegrationTests { - private ConfigurableApplicationContext context; + private @Nullable ConfigurableApplicationContext context; @BeforeEach void setup() { @@ -86,8 +87,10 @@ class DevToolPropertiesIntegrationTests { SpringApplication application = new SpringApplication(BeanConditionConfiguration.class); application.setWebApplicationType(WebApplicationType.NONE); this.context = getContext(application::run); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(MyBean.class)); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> { + assertThat(this.context).isNotNull(); + this.context.getBean(MyBean.class); + }); } @Test @@ -124,7 +127,9 @@ class DevToolPropertiesIntegrationTests { }); thread.start(); thread.join(); - return atomicReference.get(); + ConfigurableApplicationContext context = atomicReference.get(); + assertThat(context).isNotNull(); + return context; } @Configuration(proxyBeanMethods = false) diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java index a2277338060..61bd2f189a6 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java @@ -25,10 +25,12 @@ import java.util.Collections; import java.util.Map; import java.util.Properties; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.springframework.boot.SpringApplication; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.ClassPathResource; import org.springframework.mock.env.MockEnvironment; @@ -201,8 +203,8 @@ class DevToolsHomePropertiesPostProcessorTests { return getPostProcessedEnvironment(env, null); } - private ConfigurableEnvironment getPostProcessedEnvironment(Map env, Properties systemProperties) - throws Exception { + private ConfigurableEnvironment getPostProcessedEnvironment(@Nullable Map env, + @Nullable Properties systemProperties) throws Exception { if (systemProperties == null) { systemProperties = new Properties(); systemProperties.setProperty("user.home", this.home.getAbsolutePath()); @@ -210,7 +212,7 @@ class DevToolsHomePropertiesPostProcessorTests { ConfigurableEnvironment environment = new MockEnvironment(); DevToolsHomePropertiesPostProcessor postProcessor = new DevToolsHomePropertiesPostProcessor( (env != null) ? env : Collections.emptyMap(), systemProperties); - runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, null)); + runPostProcessor(() -> postProcessor.postProcessEnvironment(environment, new SpringApplication())); return environment; } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/ChangedFileTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/ChangedFileTests.java index de51027c217..a4ae95de806 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/ChangedFileTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/ChangedFileTests.java @@ -34,9 +34,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class ChangedFileTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test + @SuppressWarnings("NullAway") // Test null check void sourceDirectoryMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ChangedFile(null, new File(this.tempDir, "file"), Type.ADD)) @@ -44,6 +46,7 @@ class ChangedFileTests { } @Test + @SuppressWarnings("NullAway") // Test null check void fileMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ChangedFile(new File(this.tempDir, "directory"), null, Type.ADD)) @@ -51,6 +54,7 @@ class ChangedFileTests { } @Test + @SuppressWarnings("NullAway") // Test null check void typeMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy( diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/DirectorySnapshotTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/DirectorySnapshotTests.java index 62075c505e3..e91c218ceb2 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/DirectorySnapshotTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/DirectorySnapshotTests.java @@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class DirectorySnapshotTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; private File directory; @@ -51,6 +52,7 @@ class DirectorySnapshotTests { } @Test + @SuppressWarnings("NullAway") // Test null check void directoryMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(null)) .withMessageContaining("'directory' must not be null"); @@ -101,6 +103,7 @@ class DirectorySnapshotTests { } @Test + @SuppressWarnings("NullAway") // Test null check void getChangedFilesSnapshotMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> this.initialSnapshot.getChangedFiles(null, null)) .withMessageContaining("'snapshot' must not be null"); @@ -142,7 +145,7 @@ class DirectorySnapshotTests { return changedFile; } } - return null; + throw new AssertionError("File '%s' not found".formatted(file)); } private File createTestDirectoryStructure() throws IOException { diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSnapshotTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSnapshotTests.java index eba611ff55c..157c9c4cfb9 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSnapshotTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSnapshotTests.java @@ -42,9 +42,11 @@ class FileSnapshotTests { private static final long MODIFIED = new Date().getTime() - TimeUnit.DAYS.toMillis(10); @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test + @SuppressWarnings("NullAway") // Test null check void fileMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(null)) .withMessageContaining("'file' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java index e82987dc5d0..04668fdb3cf 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -53,11 +54,12 @@ class FileSystemWatcherTests { private final List> changes = Collections.synchronizedList(new ArrayList<>()); @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @BeforeEach void setup() { - setupWatcher(20, 10); + this.watcher = setupWatcher(20, 10); } @Test @@ -82,6 +84,7 @@ class FileSystemWatcherTests { } @Test + @SuppressWarnings("NullAway") // Test null check void listenerMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addListener(null)) .withMessageContaining("'fileChangeListener' must not be null"); @@ -95,6 +98,7 @@ class FileSystemWatcherTests { } @Test + @SuppressWarnings("NullAway") // Test null check void sourceDirectoryMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addSourceDirectory(null)) .withMessageContaining("'directory' must not be null"); @@ -149,7 +153,7 @@ class FileSystemWatcherTests { @Test void waitsForPollingInterval() throws Exception { - setupWatcher(10, 1); + this.watcher = setupWatcher(10, 1); File directory = startWithNewDirectory(); touch(new File(directory, "test1.txt")); while (this.changes.size() != 1) { @@ -162,7 +166,7 @@ class FileSystemWatcherTests { @Test void waitsForQuietPeriod() throws Exception { - setupWatcher(300, 200); + this.watcher = setupWatcher(300, 200); File directory = startWithNewDirectory(); for (int i = 0; i < 100; i++) { touch(new File(directory, i + "test.txt")); @@ -270,7 +274,7 @@ class FileSystemWatcherTests { @Test void withSnapshotRepository() throws Exception { SnapshotStateRepository repository = new TestSnapshotStateRepository(); - setupWatcher(20, 10, repository); + this.watcher = setupWatcher(20, 10, repository); File directory = new File(this.tempDir, UUID.randomUUID().toString()); directory.mkdir(); File file = touch(new File(directory, "file.txt")); @@ -280,7 +284,7 @@ class FileSystemWatcherTests { this.watcher.stopAfter(1); this.changes.clear(); File recreate = touch(new File(directory, "file.txt")); - setupWatcher(20, 10, repository); + this.watcher = setupWatcher(20, 10, repository); this.watcher.addSourceDirectory(directory); this.watcher.start(); this.watcher.stopAfter(1); @@ -290,14 +294,16 @@ class FileSystemWatcherTests { assertThat(actual).isEqualTo(expected); } - private void setupWatcher(long pollingInterval, long quietPeriod) { - setupWatcher(pollingInterval, quietPeriod, null); + private FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod) { + return setupWatcher(pollingInterval, quietPeriod, null); } - private void setupWatcher(long pollingInterval, long quietPeriod, SnapshotStateRepository snapshotStateRepository) { - this.watcher = new FileSystemWatcher(false, Duration.ofMillis(pollingInterval), Duration.ofMillis(quietPeriod), - snapshotStateRepository); - this.watcher.addListener(FileSystemWatcherTests.this.changes::add); + private FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod, + @Nullable SnapshotStateRepository snapshotStateRepository) { + FileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(pollingInterval), + Duration.ofMillis(quietPeriod), snapshotStateRepository); + watcher.addListener(FileSystemWatcherTests.this.changes::add); + return watcher; } private File startWithNewDirectory() { @@ -328,7 +334,7 @@ class FileSystemWatcherTests { private static final class TestSnapshotStateRepository implements SnapshotStateRepository { - private Object state; + private @Nullable Object state; @Override public void save(Object state) { @@ -336,7 +342,7 @@ class FileSystemWatcherTests { } @Override - public Object restore() { + public @Nullable Object restore() { return this.state; } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/FrameTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/FrameTests.java index 3b5cd3816fd..c96fb435ed1 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/FrameTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/FrameTests.java @@ -34,12 +34,14 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; class FrameTests { @Test + @SuppressWarnings("NullAway") // Test null check void payloadMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new Frame((String) null)) .withMessageContaining("'payload' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void typeMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new Frame((Frame.Type) null)) .withMessageContaining("'type' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java index b513d0eea4e..a3d4edc03f0 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java @@ -47,11 +47,13 @@ import jakarta.websocket.HandshakeResponse; import jakarta.websocket.WebSocketContainer; import org.apache.tomcat.websocket.WsWebSocketContainer; 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.Disabled; import org.junit.jupiter.api.Test; +import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.http.HttpHeaders; import org.springframework.web.client.RestTemplate; import org.springframework.web.socket.CloseStatus; @@ -223,7 +225,7 @@ class LiveReloadServerTests { class LiveReloadWebSocketHandler extends TextWebSocketHandler { - private volatile WebSocketSession session; + private volatile @Nullable WebSocketSession session; private final CountDownLatch helloLatch = new CountDownLatch(2); @@ -231,7 +233,7 @@ class LiveReloadServerTests { private final AtomicInteger pongCount = new AtomicInteger(); - private volatile CloseStatus closeStatus; + private volatile @Nullable CloseStatus closeStatus; @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { @@ -264,11 +266,15 @@ class LiveReloadServerTests { } void sendMessage(WebSocketMessage message) throws IOException { - this.session.sendMessage(message); + WebSocketSession session = this.session; + assertThat(session).isNotNull(); + session.sendMessage(message); } void close() throws IOException { - this.session.close(); + WebSocketSession session = this.session; + assertThat(session).isNotNull(); + session.close(); } List getMessages() { @@ -279,7 +285,7 @@ class LiveReloadServerTests { return this.pongCount.get(); } - CloseStatus getCloseStatus() { + @Nullable CloseStatus getCloseStatus() { return this.closeStatus; } @@ -314,7 +320,9 @@ class LiveReloadServerTests { this.webSocketContainer.connectToServer(endpoint, endpointConfig, uri); return session; }; - return getTaskExecutor().submitCompletable(connectTask); + AsyncTaskExecutor taskExecutor = getTaskExecutor(); + assertThat(taskExecutor).isNotNull(); + return taskExecutor.submitCompletable(connectTask); } private InetAddress getLocalHost() { diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploaderTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploaderTests.java index ceb1afce366..15cefc9a19f 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploaderTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploaderTests.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -65,6 +66,7 @@ class ClassPathChangeUploaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void urlMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangeUploader(null, this.requestFactory)) .withMessageContaining("'url' must not be empty"); @@ -77,6 +79,7 @@ class ClassPathChangeUploaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void requestFactoryMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new ClassPathChangeUploader("http://localhost:8080", null)) @@ -124,7 +127,7 @@ class ClassPathChangeUploaderTests { assertThat(classFiles.hasNext()).isFalse(); } - private void assertClassFile(ClassLoaderFile file, String content, Kind kind) { + private void assertClassFile(ClassLoaderFile file, @Nullable String content, Kind kind) { assertThat(file.getContents()).isEqualTo((content != null) ? content.getBytes() : null); assertThat(file.getKind()).isEqualTo(kind); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java index 094704bb728..013c6c73cf7 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java @@ -49,21 +49,27 @@ class DelayedLiveReloadTriggerTests { private static final String URL = "http://localhost:8080"; @Mock + @SuppressWarnings("NullAway.Init") private OptionalLiveReloadServer liveReloadServer; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpRequestFactory requestFactory; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpRequest errorRequest; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpRequest okRequest; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpResponse errorResponse; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpResponse okResponse; private DelayedLiveReloadTrigger trigger; @@ -74,6 +80,7 @@ class DelayedLiveReloadTriggerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void liveReloadServerMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new DelayedLiveReloadTrigger(null, this.requestFactory, URL)) @@ -81,6 +88,7 @@ class DelayedLiveReloadTriggerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void requestFactoryMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, null, URL)) @@ -88,6 +96,7 @@ class DelayedLiveReloadTriggerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void urlMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, this.requestFactory, null)) diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptorTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptorTests.java index 55687e0efa9..d9d74abf001 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptorTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptorTests.java @@ -54,9 +54,11 @@ class HttpHeaderInterceptorTests { private byte[] body; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpRequestExecution execution; @Mock + @SuppressWarnings("NullAway.Init") private ClientHttpResponse response; private MockHttpServletRequest httpRequest; @@ -72,6 +74,7 @@ class HttpHeaderInterceptorTests { } @Test + @SuppressWarnings("NullAway") // Test null check void constructorNullHeaderName() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(null, this.value)) .withMessageContaining("'name' must not be empty"); @@ -84,6 +87,7 @@ class HttpHeaderInterceptorTests { } @Test + @SuppressWarnings("NullAway") // Test null check void constructorNullHeaderValue() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(this.name, null)) .withMessageContaining("'value' must not be empty"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java index 21899871f78..8eab6adc02e 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.Set; import org.awaitility.Awaitility; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,6 +42,7 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -63,9 +65,9 @@ import static org.mockito.Mockito.mock; @ExtendWith({ OutputCaptureExtension.class, MockRestarter.class }) class RemoteClientConfigurationTests { - private AnnotationConfigServletWebServerApplicationContext context; + private @Nullable AnnotationConfigServletWebServerApplicationContext context; - private AnnotationConfigApplicationContext clientContext; + private @Nullable AnnotationConfigApplicationContext clientContext; @AfterEach void cleanup() { @@ -106,6 +108,7 @@ class RemoteClientConfigurationTests { configure(); Set changeSet = new HashSet<>(); ClassPathChangedEvent event = new ClassPathChangedEvent(this, changeSet, false); + assertThat(this.clientContext).isNotNull(); this.clientContext.publishEvent(event); LiveReloadServer server = this.clientContext.getBean(LiveReloadServer.class); Awaitility.await().atMost(Duration.ofMinutes(1)).untilAsserted(() -> then(server).should().triggerReload()); @@ -115,20 +118,26 @@ class RemoteClientConfigurationTests { void liveReloadDisabled() { configure("spring.devtools.livereload.enabled:false"); assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(OptionalLiveReloadServer.class)); + .isThrownBy(() -> getContext().getBean(OptionalLiveReloadServer.class)); } @Test void remoteRestartDisabled() { configure("spring.devtools.remote.restart.enabled:false"); assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(ClassPathFileSystemWatcher.class)); + .isThrownBy(() -> getContext().getBean(ClassPathFileSystemWatcher.class)); } private void configure(String... pairs) { configure("http://localhost", true, pairs); } + private AnnotationConfigServletWebServerApplicationContext getContext() { + AnnotationConfigServletWebServerApplicationContext context = this.context; + assertThat(context).isNotNull(); + return context; + } + private void configure(String remoteUrl, boolean setSecret, String... pairs) { this.context = new AnnotationConfigServletWebServerApplicationContext(); this.context.register(Config.class); @@ -143,7 +152,9 @@ class RemoteClientConfigurationTests { if (setSecret) { TestPropertyValues.of("spring.devtools.remote.secret:secret").applyTo(this.clientContext); } - String remoteUrlProperty = "remoteUrl:" + remoteUrl + ":" + this.context.getWebServer().getPort(); + WebServer webServer = this.context.getWebServer(); + assertThat(webServer).isNotNull(); + String remoteUrlProperty = "remoteUrl:" + remoteUrl + ":" + webServer.getPort(); TestPropertyValues.of(remoteUrlProperty).applyTo(this.clientContext); this.clientContext.refresh(); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherFilterTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherFilterTests.java index 4850d1b700c..cdcd593fac7 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherFilterTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherFilterTests.java @@ -51,9 +51,11 @@ import static org.mockito.Mockito.mock; class DispatcherFilterTests { @Mock + @SuppressWarnings("NullAway.Init") private Dispatcher dispatcher; @Mock + @SuppressWarnings("NullAway.Init") private FilterChain chain; private DispatcherFilter filter; @@ -64,6 +66,7 @@ class DispatcherFilterTests { } @Test + @SuppressWarnings("NullAway") // Test null check void dispatcherMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new DispatcherFilter(null)) .withMessageContaining("'dispatcher' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherTests.java index 1d4e4b5126f..0dbb5adc2fd 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherTests.java @@ -52,6 +52,7 @@ import static org.mockito.Mockito.withSettings; class DispatcherTests { @Mock + @SuppressWarnings("NullAway.Init") private AccessManager accessManager; private final MockHttpServletResponse response = new MockHttpServletResponse(); @@ -61,12 +62,14 @@ class DispatcherTests { private final ServerHttpResponse serverResponse = new ServletServerHttpResponse(this.response); @Test + @SuppressWarnings("NullAway") // Test null check void accessManagerMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(null, Collections.emptyList())) .withMessageContaining("'accessManager' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void mappersMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(this.accessManager, null)) .withMessageContaining("'mappers' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManagerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManagerTests.java index d97ac3ef8b8..df5a27fa77a 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManagerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManagerTests.java @@ -52,6 +52,7 @@ class HttpHeaderAccessManagerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void headerNameMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(null, SECRET)) .withMessageContaining("'headerName' must not be empty"); @@ -64,6 +65,7 @@ class HttpHeaderAccessManagerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void expectedSecretMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(HEADER, null)) .withMessageContaining("'expectedSecret' must not be empty"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpStatusHandlerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpStatusHandlerTests.java index 2c7b4d39c7b..830e66c0938 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpStatusHandlerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpStatusHandlerTests.java @@ -54,6 +54,7 @@ class HttpStatusHandlerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void statusMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpStatusHandler(null)) .withMessageContaining("'status' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapperTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapperTests.java index ee9584ee103..c96abf43051 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapperTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapperTests.java @@ -38,6 +38,7 @@ class UrlHandlerMapperTests { private final Handler handler = mock(Handler.class); @Test + @SuppressWarnings("NullAway") // Test null check void requestUriMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new UrlHandlerMapper(null, this.handler)) .withMessageContaining("'url' must not be empty"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java index e52ab7513fd..1f3f269c198 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java @@ -43,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat; class ChangeableUrlsTests { @TempDir + @SuppressWarnings("NullAway.Init") File tempDir; @Test diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MainMethodTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MainMethodTests.java index d8ced0b9d55..1a619cfe38b 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MainMethodTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MainMethodTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -45,6 +46,7 @@ class MainMethodTests { } @Test + @SuppressWarnings("NullAway") // Test null check void threadMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new MainMethod(null)) .withMessageContaining("'thread' must not be null"); @@ -90,9 +92,9 @@ class MainMethodTests { private final Runnable runnable; - private Exception exception; + private @Nullable Exception exception; - private MainMethod mainMethod; + private @Nullable MainMethod mainMethod; TestThread(Runnable runnable) { this.runnable = runnable; @@ -104,7 +106,9 @@ class MainMethodTests { if (this.exception != null) { ReflectionUtils.rethrowRuntimeException(this.exception); } - return this.mainMethod; + MainMethod mainMethod = this.mainMethod; + assertThat(mainMethod).isNotNull(); + return mainMethod; } @Override diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartScopeInitializerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartScopeInitializerTests.java index ecce6449638..0138d2695a5 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartScopeInitializerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartScopeInitializerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; @@ -37,9 +38,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ class RestartScopeInitializerTests { - private static AtomicInteger createCount; + private static @Nullable AtomicInteger createCount; - private static AtomicInteger refreshCount; + private static @Nullable AtomicInteger refreshCount; @Test void restartScope() { @@ -73,11 +74,13 @@ class RestartScopeInitializerTests { static class ScopeTestBean implements ApplicationListener { ScopeTestBean() { + assertThat(createCount).isNotNull(); createCount.incrementAndGet(); } @Override public void onApplicationEvent(ContextRefreshedEvent event) { + assertThat(refreshCount).isNotNull(); refreshCount.incrementAndGet(); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestarterTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestarterTests.java index 6b07023e1d2..82be46f6442 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestarterTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestarterTests.java @@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.assertj.core.api.InstanceOfAssertFactories; 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; @@ -111,6 +112,7 @@ class RestarterTests { } @Test + @SuppressWarnings("NullAway") // Test null check void addUrlsMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addUrls(null)) .withMessageContaining("'urls' must not be null"); @@ -124,10 +126,12 @@ class RestarterTests { restarter.addUrls(urls); restarter.restart(); ClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader(); + assertThat(classLoader).isNotNull(); assertThat(((URLClassLoader) classLoader).getURLs()[0]).isEqualTo(url); } @Test + @SuppressWarnings("NullAway") // Test null check void addClassLoaderFilesMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addClassLoaderFiles(null)) .withMessageContaining("'classLoaderFiles' must not be null"); @@ -141,6 +145,7 @@ class RestarterTests { restarter.addClassLoaderFiles(classLoaderFiles); restarter.restart(); ClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader(); + assertThat(classLoader).isNotNull(); assertThat(classLoader.getResourceAsStream("f")).hasContent("abc"); } @@ -239,7 +244,7 @@ class RestarterTests { static class TestableRestarter extends Restarter { - private ClassLoader relaunchClassLoader; + private @Nullable ClassLoader relaunchClassLoader; TestableRestarter() { this(Thread.currentThread(), new String[] {}, false, new MockRestartInitializer()); @@ -262,7 +267,7 @@ class RestarterTests { } @Override - protected Throwable relaunch(ClassLoader classLoader) { + protected @Nullable Throwable relaunch(ClassLoader classLoader) { this.relaunchClassLoader = classLoader; return null; } @@ -271,7 +276,7 @@ class RestarterTests { protected void stop() { } - ClassLoader getRelaunchClassLoader() { + @Nullable ClassLoader getRelaunchClassLoader() { return this.relaunchClassLoader; } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java index 73602974fb7..ad081ee2b1e 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.devtools.restart; import java.util.concurrent.CountDownLatch; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -55,7 +56,9 @@ class SilentExitExceptionHandlerTests { }; SilentExitExceptionHandler.setup(testThread); testThread.startAndJoin(); - assertThat(testThread.getThrown().getMessage()).isEqualTo("Expected"); + Throwable thrown = testThread.getThrown(); + assertThat(thrown).isNotNull(); + assertThat(thrown.getMessage()).isEqualTo("Expected"); } @Test @@ -78,13 +81,13 @@ class SilentExitExceptionHandlerTests { static class TestThread extends Thread { - private Throwable thrown; + private @Nullable Throwable thrown; TestThread() { setUncaughtExceptionHandler((thread, exception) -> TestThread.this.thrown = exception); } - Throwable getThrown() { + @Nullable Throwable getThrown() { return this.thrown; } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileTests.java index 63c0e3921c6..e1a4de611c3 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileTests.java @@ -33,24 +33,28 @@ class ClassLoaderFileTests { public static final byte[] BYTES = "ABC".getBytes(); @Test + @SuppressWarnings("NullAway") // Test null check void kindMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(null, null)) .withMessageContaining("'kind' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void addedContentsMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.ADDED, null)) .withMessageContaining("'contents' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void modifiedContentsMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.MODIFIED, null)) .withMessageContaining("'contents' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void deletedContentsMustBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.DELETED, new byte[10])) .withMessageContaining("'contents' must be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFilesTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFilesTests.java index 1fa44ade46b..b68ac5e5abd 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFilesTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFilesTests.java @@ -41,12 +41,14 @@ class ClassLoaderFilesTests { private final ClassLoaderFiles files = new ClassLoaderFiles(); @Test + @SuppressWarnings("NullAway") // Test null check void addFileNameMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile(null, mock(ClassLoaderFile.class))) .withMessageContaining("'name' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void addFileFileMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile("test", null)) .withMessageContaining("'file' must not be null"); @@ -151,6 +153,7 @@ class ClassLoaderFilesTests { } @Test + @SuppressWarnings("NullAway") // Test null check void classLoaderFilesMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFiles(null)) .withMessageContaining("'classLoaderFiles' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java index b82377bf5ad..14ca1b56ccd 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java @@ -102,12 +102,14 @@ class RestartClassLoaderTests { } @Test + @SuppressWarnings("NullAway") // Test null check void parentMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new RestartClassLoader(null, new URL[] {})) .withMessageContaining("'parent' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void updatedFilesMustNotBeNull() { assertThatIllegalArgumentException() .isThrownBy(() -> new RestartClassLoader(this.parentClassLoader, new URL[] {}, null)) @@ -164,6 +166,7 @@ class RestartClassLoaderTests { byte[] bytes = "abc".getBytes(); this.updatedFiles.addFile(name, new ClassLoaderFile(Kind.MODIFIED, bytes)); URL resource = this.reloadClassLoader.getResource(name); + assertThat(resource).isNotNull(); assertThat(FileCopyUtils.copyToByteArray(resource.openStream())).isEqualTo(bytes); } diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandlerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandlerTests.java index cfdda74759f..e6c53b04d97 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandlerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandlerTests.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.mock; class HttpRestartServerHandlerTests { @Test + @SuppressWarnings("NullAway") // Test null check void serverMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServerHandler(null)) .withMessageContaining("'server' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerTests.java index 6da9ef7781e..536ad8e6bfa 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerTests.java @@ -48,6 +48,7 @@ import static org.mockito.BDDMockito.then; class HttpRestartServerTests { @Mock + @SuppressWarnings("NullAway.Init") private RestartServer delegate; private HttpRestartServer server; @@ -58,12 +59,14 @@ class HttpRestartServerTests { } @Test + @SuppressWarnings("NullAway") // Test null check void sourceDirectoryUrlFilterMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((SourceDirectoryUrlFilter) null)) .withMessageContaining("'sourceDirectoryUrlFilter' must not be null"); } @Test + @SuppressWarnings("NullAway") // Test null check void restartServerMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((RestartServer) null)) .withMessageContaining("'restartServer' must not be null"); diff --git a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/RestartServerTests.java b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/RestartServerTests.java index e6fe0b9cd85..5851e7f4d82 100644 --- a/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/RestartServerTests.java +++ b/module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/RestartServerTests.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -43,6 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class RestartServerTests { @Test + @SuppressWarnings("NullAway") // Test null check void sourceDirectoryUrlFilterMustNotBeNull() { assertThatIllegalArgumentException().isThrownBy(() -> new RestartServer((SourceDirectoryUrlFilter) null)) .withMessageContaining("'sourceDirectoryUrlFilter' must not be null"); @@ -110,9 +112,9 @@ class RestartServerTests { super(sourceDirectoryUrlFilter, classLoader); } - private Set restartUrls; + private @Nullable Set restartUrls; - private ClassLoaderFiles restartFiles; + private @Nullable ClassLoaderFiles restartFiles; @Override protected void restart(Set urls, ClassLoaderFiles files) {