diff --git a/module/spring-boot-reactor-netty/build.gradle b/module/spring-boot-reactor-netty/build.gradle index 3216e049c98..55c1e0e8c0e 100644 --- a/module/spring-boot-reactor-netty/build.gradle +++ b/module/spring-boot-reactor-netty/build.gradle @@ -29,6 +29,8 @@ dependencies { api("io.projectreactor.netty:reactor-netty-http") api("org.springframework:spring-web") + compileOnly("com.google.code.findbugs:jsr305") + implementation(project(":module:spring-boot-netty")) optional(project(":core:spring-boot-autoconfigure")) diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/CompressionCustomizer.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/CompressionCustomizer.java index 3cb03a4590b..61c340482e9 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/CompressionCustomizer.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/CompressionCustomizer.java @@ -22,6 +22,7 @@ import java.util.function.BiPredicate; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; +import org.jspecify.annotations.Nullable; import reactor.netty.http.server.HttpServer; import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; @@ -82,7 +83,7 @@ final class CompressionCustomizer implements NettyServerCustomizer { }; } - private CompressionPredicate getExcludedUserAgentsPredicate(String[] excludedUserAgents) { + private CompressionPredicate getExcludedUserAgentsPredicate(String @Nullable [] excludedUserAgents) { if (ObjectUtils.isEmpty(excludedUserAgents)) { return ALWAYS_COMPRESS; } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/GracefulShutdown.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/GracefulShutdown.java index 1462d551fed..dea35f53d40 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/GracefulShutdown.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/GracefulShutdown.java @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.netty.DisposableServer; import org.springframework.boot.web.server.GracefulShutdownCallback; @@ -35,13 +36,13 @@ final class GracefulShutdown { private static final Log logger = LogFactory.getLog(GracefulShutdown.class); - private final Supplier disposableServer; + private final Supplier<@Nullable DisposableServer> disposableServer; - private volatile Thread shutdownThread; + private volatile @Nullable Thread shutdownThread; private volatile boolean shuttingDown; - GracefulShutdown(Supplier disposableServer) { + GracefulShutdown(Supplier<@Nullable DisposableServer> disposableServer) { this.disposableServer = disposableServer; } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactory.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactory.java index 727f3011897..d762c05b926 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactory.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactory.java @@ -25,9 +25,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.jspecify.annotations.Nullable; import reactor.netty.http.HttpProtocol; import reactor.netty.http.server.HttpServer; +import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.WebServer; @@ -53,13 +55,11 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact private final List routeProviders = new ArrayList<>(); - private Duration lifecycleTimeout; + private @Nullable Duration lifecycleTimeout; private boolean useForwardHeaders; - private ReactorResourceFactory resourceFactory; - - private Shutdown shutdown; + private @Nullable ReactorResourceFactory resourceFactory; public NettyReactiveWebServerFactory() { } @@ -79,7 +79,7 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact } NettyWebServer createNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, - Duration lifecycleTimeout, Shutdown shutdown) { + @Nullable Duration lifecycleTimeout, Shutdown shutdown) { return new NettyWebServer(httpServer, handlerAdapter, lifecycleTimeout, shutdown, this.resourceFactory); } @@ -127,7 +127,7 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact * server. * @param lifecycleTimeout the lifecycle timeout */ - public void setLifecycleTimeout(Duration lifecycleTimeout) { + public void setLifecycleTimeout(@Nullable Duration lifecycleTimeout) { this.lifecycleTimeout = lifecycleTimeout; } @@ -145,24 +145,15 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact * @param resourceFactory the server resources * @since 4.0.0 */ - public void setResourceFactory(ReactorResourceFactory resourceFactory) { + public void setResourceFactory(@Nullable ReactorResourceFactory resourceFactory) { this.resourceFactory = resourceFactory; } - @Override - public void setShutdown(Shutdown shutdown) { - this.shutdown = shutdown; - } - - @Override - public Shutdown getShutdown() { - return this.shutdown; - } - private HttpServer createHttpServer() { HttpServer server = HttpServer.create().bindAddress(this::getListenAddress); - if (Ssl.isEnabled(getSsl())) { - server = customizeSslConfiguration(server); + Ssl ssl = getSsl(); + if (Ssl.isEnabled(ssl)) { + server = customizeSslConfiguration(server, ssl); } if (getCompression() != null && getCompression().getEnabled()) { CompressionCustomizer compressionCustomizer = new CompressionCustomizer(getCompression()); @@ -172,19 +163,22 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact return applyCustomizers(server); } - private HttpServer customizeSslConfiguration(HttpServer httpServer) { - SslServerCustomizer customizer = new SslServerCustomizer(getHttp2(), getSsl().getClientAuth(), getSslBundle(), + private HttpServer customizeSslConfiguration(HttpServer httpServer, Ssl ssl) { + SslServerCustomizer customizer = new SslServerCustomizer(getHttp2(), ssl.getClientAuth(), getSslBundle(), getServerNameSslBundles()); - addBundleUpdateHandler(null, getSsl().getBundle(), customizer); - getSsl().getServerNameBundles() + addBundleUpdateHandler(null, ssl.getBundle(), customizer); + ssl.getServerNameBundles() .forEach((serverNameSslBundle) -> addBundleUpdateHandler(serverNameSslBundle.serverName(), serverNameSslBundle.bundle(), customizer)); return customizer.apply(httpServer); } - private void addBundleUpdateHandler(String serverName, String bundleName, SslServerCustomizer customizer) { + private void addBundleUpdateHandler(@Nullable String serverName, @Nullable String bundleName, + SslServerCustomizer customizer) { if (StringUtils.hasText(bundleName)) { - getSslBundles().addBundleUpdateHandler(bundleName, + SslBundles sslBundles = getSslBundles(); + Assert.state(sslBundles != null, "'sslBundles' must not be null"); + sslBundles.addBundleUpdateHandler(bundleName, (sslBundle) -> customizer.updateSslBundle(serverName, sslBundle)); } } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java index 5461bdb0953..f3beca884e6 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java @@ -28,6 +28,7 @@ import io.netty.channel.unix.Errors.NativeIoException; import io.netty.util.concurrent.DefaultEventExecutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.netty.ChannelBindException; import reactor.netty.DisposableServer; @@ -72,15 +73,15 @@ public class NettyWebServer implements WebServer { private final BiFunction> handler; - private final Duration lifecycleTimeout; + private final @Nullable Duration lifecycleTimeout; - private final GracefulShutdown gracefulShutdown; + private final @Nullable GracefulShutdown gracefulShutdown; - private final ReactorResourceFactory resourceFactory; + private final @Nullable ReactorResourceFactory resourceFactory; private List routeProviders = Collections.emptyList(); - private volatile DisposableServer disposableServer; + private volatile @Nullable DisposableServer disposableServer; /** * Creates a new {@code NettyWebServer} instance. @@ -92,8 +93,9 @@ public class NettyWebServer implements WebServer { * resources}, may be {@code null} * @since 4.0.0 */ - public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, Duration lifecycleTimeout, - Shutdown shutdown, ReactorResourceFactory resourceFactory) { + public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, + @Nullable Duration lifecycleTimeout, @Nullable Shutdown shutdown, + @Nullable ReactorResourceFactory resourceFactory) { Assert.notNull(httpServer, "'httpServer' must not be null"); Assert.notNull(handlerAdapter, "'handlerAdapter' must not be null"); this.lifecycleTimeout = lifecycleTimeout; @@ -138,6 +140,7 @@ public class NettyWebServer implements WebServer { } protected String getStartedLogMessage() { + Assert.state(this.disposableServer != null, "'disposableServer' must not be null"); return getStartedOnMessage(this.disposableServer); } @@ -171,7 +174,7 @@ public class NettyWebServer implements WebServer { return server.bindNow(); } - private boolean isPermissionDenied(Throwable bindExceptionCause) { + private boolean isPermissionDenied(@Nullable Throwable bindExceptionCause) { try { if (bindExceptionCause instanceof NativeIoException nativeException) { return nativeException.expectedErr() == ERROR_NO_EACCES; diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/SslServerCustomizer.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/SslServerCustomizer.java index 54a17d8007b..ec821c4581f 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/SslServerCustomizer.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/SslServerCustomizer.java @@ -22,6 +22,7 @@ import java.util.Map; import io.netty.handler.ssl.ClientAuth; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import reactor.netty.http.Http11SslContextSpec; import reactor.netty.http.Http2SslContextSpec; import reactor.netty.http.server.HttpServer; @@ -52,7 +53,7 @@ public class SslServerCustomizer implements NettyServerCustomizer { private static final Log logger = LogFactory.getLog(SslServerCustomizer.class); - private final Http2 http2; + private final @Nullable Http2 http2; private final ClientAuth clientAuth; @@ -60,7 +61,7 @@ public class SslServerCustomizer implements NettyServerCustomizer { private final Map serverNameSslProviders; - public SslServerCustomizer(Http2 http2, Ssl.ClientAuth clientAuth, SslBundle sslBundle, + public SslServerCustomizer(@Nullable Http2 http2, Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle, Map serverNameSslBundles) { this.http2 = http2; this.clientAuth = Ssl.ClientAuth.map(clientAuth, ClientAuth.NONE, ClientAuth.OPTIONAL, ClientAuth.REQUIRE); @@ -82,7 +83,7 @@ public class SslServerCustomizer implements NettyServerCustomizer { }); } - void updateSslBundle(String serverName, SslBundle sslBundle) { + void updateSslBundle(@Nullable String serverName, SslBundle sslBundle) { logger.debug("SSL Bundle has been updated, reloading SSL configuration"); if (serverName == null) { this.sslProvider = createSslProvider(sslBundle); diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizer.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizer.java index 9c812f60fc6..aceff395650 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizer.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizer.java @@ -66,7 +66,7 @@ public class NettyReactiveWebServerFactoryCustomizer map.from(this.nettyProperties::getIdleTimeout).to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout)); map.from(this.nettyProperties::getMaxKeepAliveRequests) .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); - if (this.serverProperties.getHttp2() != null && this.serverProperties.getHttp2().isEnabled()) { + if (this.serverProperties.getHttp2().isEnabled()) { map.from(this.serverProperties.getMaxHttpRequestHeaderSize()) .to((size) -> customizeHttp2MaxHeaderSize(factory, size.toBytes())); } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerProperties.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerProperties.java index dcc548ea23d..3273c84ec4c 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerProperties.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerProperties.java @@ -18,6 +18,8 @@ package org.springframework.boot.reactor.netty.autoconfigure; import java.time.Duration; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.unit.DataSize; @@ -55,7 +57,7 @@ public class NettyServerProperties { /** * Connection timeout of the Netty channel. */ - private Duration connectionTimeout; + private @Nullable Duration connectionTimeout; /** * Maximum content length of an H2C upgrade request. @@ -76,7 +78,7 @@ public class NettyServerProperties { * Maximum number of requests that can be made per connection. By default, a * connection serves unlimited number of requests. */ - private Integer maxKeepAliveRequests; + private @Nullable Integer maxKeepAliveRequests; /** * Whether to validate headers when decoding requests. @@ -86,13 +88,13 @@ public class NettyServerProperties { /** * Idle timeout of the Netty channel. When not specified, an infinite timeout is used. */ - private Duration idleTimeout; + private @Nullable Duration idleTimeout; - public Duration getConnectionTimeout() { + public @Nullable Duration getConnectionTimeout() { return this.connectionTimeout; } - public void setConnectionTimeout(Duration connectionTimeout) { + public void setConnectionTimeout(@Nullable Duration connectionTimeout) { this.connectionTimeout = connectionTimeout; } @@ -120,11 +122,11 @@ public class NettyServerProperties { this.maxInitialLineLength = maxInitialLineLength; } - public Integer getMaxKeepAliveRequests() { + public @Nullable Integer getMaxKeepAliveRequests() { return this.maxKeepAliveRequests; } - public void setMaxKeepAliveRequests(Integer maxKeepAliveRequests) { + public void setMaxKeepAliveRequests(@Nullable Integer maxKeepAliveRequests) { this.maxKeepAliveRequests = maxKeepAliveRequests; } @@ -136,11 +138,11 @@ public class NettyServerProperties { this.validateHeaders = validateHeaders; } - public Duration getIdleTimeout() { + public @Nullable Duration getIdleTimeout() { return this.idleTimeout; } - public void setIdleTimeout(Duration idleTimeout) { + public void setIdleTimeout(@Nullable Duration idleTimeout) { this.idleTimeout = idleTimeout; } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyProperties.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyProperties.java index a58d2fe0d46..96800f1ee56 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyProperties.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyProperties.java @@ -18,6 +18,8 @@ package org.springframework.boot.reactor.netty.autoconfigure; import java.time.Duration; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -32,13 +34,13 @@ public class ReactorNettyProperties { /** * Amount of time to wait before shutting down resources. */ - private Duration shutdownQuietPeriod; + private @Nullable Duration shutdownQuietPeriod; - public Duration getShutdownQuietPeriod() { + public @Nullable Duration getShutdownQuietPeriod() { return this.shutdownQuietPeriod; } - public void setShutdownQuietPeriod(Duration shutdownQuietPeriod) { + public void setShutdownQuietPeriod(@Nullable Duration shutdownQuietPeriod) { this.shutdownQuietPeriod = shutdownQuietPeriod; } diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/package-info.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/package-info.java index fde4b384c4d..454be19eb6f 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/package-info.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/package-info.java @@ -17,4 +17,7 @@ /** * Auto-configuration for Reactor Netty actuator web concerns. */ +@NullMarked package org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/package-info.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/package-info.java index 4f8adb491b9..01149914ce1 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/package-info.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/package-info.java @@ -17,4 +17,7 @@ /** * Auto-configuration for Reactor Netty. */ +@NullMarked package org.springframework.boot.reactor.netty.autoconfigure; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/package-info.java b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/package-info.java index 7ce764f7bc7..edb12975a78 100644 --- a/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/package-info.java +++ b/module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/package-info.java @@ -16,6 +16,8 @@ /** * Reactive web server implementation backed by Netty. - * */ +@NullMarked package org.springframework.boot.reactor.netty; + +import org.jspecify.annotations.NullMarked;