diff --git a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.kt b/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.kt index 04a571c1db1..e7127f6331d 100644 --- a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.kt +++ b/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.kt @@ -16,14 +16,14 @@ package org.springframework.boot.docs.howto.webserver.configure -import org.springframework.boot.web.server.WebServerFactoryCustomizer import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory +import org.springframework.boot.web.server.WebServerFactoryCustomizer import org.springframework.stereotype.Component @Component -class MyTomcatWebServerCustomizer : WebServerFactoryCustomizer { +class MyTomcatWebServerCustomizer : WebServerFactoryCustomizer { - override fun customize(factory: TomcatServletWebServerFactory?) { + override fun customize(factory: TomcatServletWebServerFactory) { // customize the factory here } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java index 8550a132f20..2b1ca3ce3d6 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.web.error.ErrorPage; @@ -49,19 +51,19 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab private int port = 8080; - private InetAddress address; + private @Nullable InetAddress address; private Set errorPages = new LinkedHashSet<>(); - private Ssl ssl; + private @Nullable Ssl ssl; - private SslBundles sslBundles; + private @Nullable SslBundles sslBundles; - private Http2 http2; + private @Nullable Http2 http2; - private Compression compression; + private @Nullable Compression compression; - private String serverHeader; + private @Nullable String serverHeader; private Shutdown shutdown = Shutdown.IMMEDIATE; @@ -97,12 +99,12 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab * Return the address that the web server binds to. * @return the address */ - public InetAddress getAddress() { + public @Nullable InetAddress getAddress() { return this.address; } @Override - public void setAddress(InetAddress address) { + public void setAddress(@Nullable InetAddress address) { this.address = address; } @@ -127,12 +129,12 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab this.errorPages.addAll(Arrays.asList(errorPages)); } - public Ssl getSsl() { + public @Nullable Ssl getSsl() { return this.ssl; } @Override - public void setSsl(Ssl ssl) { + public void setSsl(@Nullable Ssl ssl) { this.ssl = ssl; } @@ -141,39 +143,39 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab * @return the {@link SslBundles} or {@code null} * @since 3.2.0 */ - public SslBundles getSslBundles() { + public @Nullable SslBundles getSslBundles() { return this.sslBundles; } @Override - public void setSslBundles(SslBundles sslBundles) { + public void setSslBundles(@Nullable SslBundles sslBundles) { this.sslBundles = sslBundles; } - public Http2 getHttp2() { + public @Nullable Http2 getHttp2() { return this.http2; } @Override - public void setHttp2(Http2 http2) { + public void setHttp2(@Nullable Http2 http2) { this.http2 = http2; } - public Compression getCompression() { + public @Nullable Compression getCompression() { return this.compression; } @Override - public void setCompression(Compression compression) { + public void setCompression(@Nullable Compression compression) { this.compression = compression; } - public String getServerHeader() { + public @Nullable String getServerHeader() { return this.serverHeader; } @Override - public void setServerHeader(String serverHeader) { + public void setServerHeader(@Nullable String serverHeader) { this.serverHeader = serverHeader; } @@ -200,10 +202,13 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab } protected final Map getServerNameSslBundles() { + Assert.state(this.ssl != null, "'ssl' must not be null"); return this.ssl.getServerNameBundles() .stream() - .collect(Collectors.toMap(ServerNameSslBundle::serverName, - (serverNameSslBundle) -> this.sslBundles.getBundle(serverNameSslBundle.bundle()))); + .collect(Collectors.toMap(ServerNameSslBundle::serverName, (serverNameSslBundle) -> { + Assert.state(this.sslBundles != null, "'sslBundles' must not be null"); + return this.sslBundles.getBundle(serverNameSslBundle.bundle()); + })); } /** diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Compression.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Compression.java index 0b2abc03070..76a530ce6d1 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Compression.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Compression.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationPropertiesSource; import org.springframework.util.unit.DataSize; @@ -44,7 +46,7 @@ public class Compression { /** * Comma-separated list of user agents for which responses should not be compressed. */ - private String[] excludedUserAgents = null; + private String @Nullable [] excludedUserAgents; /** * Minimum "Content-Length" value that is required for compression to be performed. @@ -75,11 +77,11 @@ public class Compression { this.mimeTypes = mimeTypes; } - public String[] getExcludedUserAgents() { + public String @Nullable [] getExcludedUserAgents() { return this.excludedUserAgents; } - public void setExcludedUserAgents(String[] excludedUserAgents) { + public void setExcludedUserAgents(String @Nullable [] excludedUserAgents) { this.excludedUserAgents = excludedUserAgents; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/ConfigurableWebServerFactory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/ConfigurableWebServerFactory.java index b3c3642a206..c154245c9bd 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/ConfigurableWebServerFactory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/ConfigurableWebServerFactory.java @@ -19,6 +19,8 @@ package org.springframework.boot.web.server; import java.net.InetAddress; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.web.error.ErrorPage; import org.springframework.boot.web.error.ErrorPageRegistry; @@ -46,7 +48,7 @@ public interface ConfigurableWebServerFactory extends WebServerFactory, ErrorPag * Sets the specific network address that the server should bind to. * @param address the address to set (defaults to {@code null}) */ - void setAddress(InetAddress address); + void setAddress(@Nullable InetAddress address); /** * Sets the error pages that will be used when handling exceptions. @@ -58,33 +60,33 @@ public interface ConfigurableWebServerFactory extends WebServerFactory, ErrorPag * Sets the SSL configuration that will be applied to the server's default connector. * @param ssl the SSL configuration */ - void setSsl(Ssl ssl); + void setSsl(@Nullable Ssl ssl); /** * Sets the SSL bundles that can be used to configure SSL connections. * @param sslBundles the SSL bundles * @since 3.1.0 */ - void setSslBundles(SslBundles sslBundles); + void setSslBundles(@Nullable SslBundles sslBundles); /** * Sets the HTTP/2 configuration that will be applied to the server. * @param http2 the HTTP/2 configuration */ - void setHttp2(Http2 http2); + void setHttp2(@Nullable Http2 http2); /** * Sets the compression configuration that will be applied to the server's default * connector. * @param compression the compression configuration */ - void setCompression(Compression compression); + void setCompression(@Nullable Compression compression); /** * Sets the server header value. * @param serverHeader the server header value */ - void setServerHeader(String serverHeader); + void setServerHeader(@Nullable String serverHeader); /** * Sets the shutdown configuration that will be applied to the server. diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Cookie.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Cookie.java index ad77838415d..8214f5cb770 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Cookie.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Cookie.java @@ -19,6 +19,8 @@ package org.springframework.boot.web.server; import java.time.Duration; import java.time.temporal.ChronoUnit; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationPropertiesSource; import org.springframework.boot.convert.DurationUnit; @@ -37,32 +39,32 @@ public class Cookie { /** * Name for the cookie. */ - private String name; + private @Nullable String name; /** * Domain for the cookie. */ - private String domain; + private @Nullable String domain; /** * Path of the cookie. */ - private String path; + private @Nullable String path; /** * Whether to use "HttpOnly" cookies for the cookie. */ - private Boolean httpOnly; + private @Nullable Boolean httpOnly; /** * Whether to always mark the cookie as secure. */ - private Boolean secure; + private @Nullable Boolean secure; /** * Whether the generated cookie carries the Partitioned attribute. */ - private Boolean partitioned; + private @Nullable Boolean partitioned; /** * Maximum age of the cookie. If a duration suffix is not specified, seconds will be @@ -71,74 +73,74 @@ public class Cookie { * means no "Max-Age". */ @DurationUnit(ChronoUnit.SECONDS) - private Duration maxAge; + private @Nullable Duration maxAge; /** * SameSite setting for the cookie. */ - private SameSite sameSite; + private @Nullable SameSite sameSite; - 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 String getDomain() { + public @Nullable String getDomain() { return this.domain; } - public void setDomain(String domain) { + public void setDomain(@Nullable String domain) { this.domain = domain; } - public String getPath() { + public @Nullable String getPath() { return this.path; } - public void setPath(String path) { + public void setPath(@Nullable String path) { this.path = path; } - public Boolean getHttpOnly() { + public @Nullable Boolean getHttpOnly() { return this.httpOnly; } - public void setHttpOnly(Boolean httpOnly) { + public void setHttpOnly(@Nullable Boolean httpOnly) { this.httpOnly = httpOnly; } - public Boolean getSecure() { + public @Nullable Boolean getSecure() { return this.secure; } - public void setSecure(Boolean secure) { + public void setSecure(@Nullable Boolean secure) { this.secure = secure; } - public Duration getMaxAge() { + public @Nullable Duration getMaxAge() { return this.maxAge; } - public void setMaxAge(Duration maxAge) { + public void setMaxAge(@Nullable Duration maxAge) { this.maxAge = maxAge; } - public SameSite getSameSite() { + public @Nullable SameSite getSameSite() { return this.sameSite; } - public void setSameSite(SameSite sameSite) { + public void setSameSite(@Nullable SameSite sameSite) { this.sameSite = sameSite; } - public Boolean getPartitioned() { + public @Nullable Boolean getPartitioned() { return this.partitioned; } - public void setPartitioned(Boolean partitioned) { + public void setPartitioned(@Nullable Boolean partitioned) { this.partitioned = partitioned; } @@ -170,13 +172,13 @@ public class Cookie { */ STRICT("Strict"); - private final String attributeValue; + private @Nullable final String attributeValue; - SameSite(String attributeValue) { + SameSite(@Nullable String attributeValue) { this.attributeValue = attributeValue; } - public String attributeValue() { + public @Nullable String attributeValue() { return this.attributeValue; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/MimeMappings.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/MimeMappings.java index 196e2a29a2f..6a19cc48b72 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/MimeMappings.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/MimeMappings.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.core.io.ClassPathResource; @@ -91,7 +93,7 @@ public sealed class MimeMappings implements Iterable { * @param mimeType the mime type to map * @return any previous mapping or {@code null} */ - public String add(String extension, String mimeType) { + public @Nullable String add(String extension, String mimeType) { Assert.notNull(extension, "'extension' must not be null"); Assert.notNull(mimeType, "'mimeType' must not be null"); Mapping previous = this.map.put(extension.toLowerCase(Locale.ENGLISH), new Mapping(extension, mimeType)); @@ -103,7 +105,7 @@ public sealed class MimeMappings implements Iterable { * @param extension the file extension (excluding '.') * @return the removed mime mapping or {@code null} if no item was removed */ - public String remove(String extension) { + public @Nullable String remove(String extension) { Assert.notNull(extension, "'extension' must not be null"); Mapping previous = this.map.remove(extension.toLowerCase(Locale.ENGLISH)); return (previous != null) ? previous.getMimeType() : null; @@ -114,7 +116,7 @@ public sealed class MimeMappings implements Iterable { * @param extension the file extension (excluding '.') * @return a mime mapping or {@code null} */ - public String get(String extension) { + public @Nullable String get(String extension) { Assert.notNull(extension, "'extension' must not be null"); Mapping mapping = this.map.get(extension.toLowerCase(Locale.ENGLISH)); return (mapping != null) ? mapping.getMimeType() : null; @@ -281,7 +283,7 @@ public sealed class MimeMappings implements Iterable { COMMON = unmodifiableMappings(mappings); } - private volatile Map loaded; + private volatile @Nullable Map loaded; DefaultMimeMappings() { super(new MimeMappings(), false); @@ -293,7 +295,7 @@ public sealed class MimeMappings implements Iterable { } @Override - public String get(String extension) { + public @Nullable String get(String extension) { Assert.notNull(extension, "'extension' must not be null"); extension = extension.toLowerCase(Locale.ENGLISH); Map loaded = this.loaded; @@ -308,7 +310,7 @@ public sealed class MimeMappings implements Iterable { return get(loaded, extension); } - private String get(Map mappings, String extension) { + private @Nullable String get(Map mappings, String extension) { Mapping mapping = mappings.get(extension); return (mapping != null) ? mapping.getMimeType() : null; } @@ -357,13 +359,13 @@ public sealed class MimeMappings implements Iterable { } @Override - public String add(String extension, String mimeType) { + public @Nullable String add(String extension, String mimeType) { copyIfNecessary(); return super.add(extension, mimeType); } @Override - public String remove(String extension) { + public @Nullable String remove(String extension) { copyIfNecessary(); return super.remove(extension); } @@ -375,7 +377,7 @@ public sealed class MimeMappings implements Iterable { } @Override - public String get(String extension) { + public @Nullable String get(String extension) { return !this.copied.get() ? this.source.get(extension) : super.get(extension); } @@ -394,7 +396,7 @@ public sealed class MimeMappings implements Iterable { static class MimeMappingsRuntimeHints implements RuntimeHintsRegistrar { @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { hints.resources() .registerPattern("org/springframework/boot/web/server/" + DefaultMimeMappings.MIME_MAPPINGS_PROPERTIES); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseException.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseException.java index a88acfca18a..baae8a7b6b4 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseException.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseException.java @@ -21,6 +21,8 @@ import java.util.Locale; import java.util.function.Consumer; import java.util.function.IntSupplier; +import org.jspecify.annotations.Nullable; + /** * A {@code PortInUseException} is thrown when a web server fails to start due to a port * already being in use. @@ -46,7 +48,7 @@ public class PortInUseException extends WebServerException { * @param port the port that was in use * @param cause the cause of the exception */ - public PortInUseException(int port, Throwable cause) { + public PortInUseException(int port, @Nullable Throwable cause) { super("Port " + port + " is already in use", cause); this.port = port; } @@ -82,7 +84,8 @@ public class PortInUseException extends WebServerException { public static void ifPortBindingException(Exception ex, Consumer action) { ifCausedBy(ex, BindException.class, (bindException) -> { // bind exception can be also thrown because an address can't be assigned - if (bindException.getMessage().toLowerCase(Locale.ROOT).contains("in use")) { + String message = bindException.getMessage(); + if (message != null && message.toLowerCase(Locale.ROOT).contains("in use")) { action.accept(bindException); } }); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Ssl.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Ssl.java index dd374fb0add..04d6aeea794 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Ssl.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Ssl.java @@ -19,7 +19,10 @@ package org.springframework.boot.web.server; import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationPropertiesSource; +import org.springframework.lang.Contract; /** * Simple server-independent abstraction for SSL configuration. @@ -41,92 +44,92 @@ public class Ssl { /** * Name of a configured SSL bundle. */ - private String bundle; + private @Nullable String bundle; /** * Client authentication mode. Requires a trust store. */ - private ClientAuth clientAuth; + private @Nullable ClientAuth clientAuth; /** * Supported SSL ciphers. */ - private String[] ciphers; + private String @Nullable [] ciphers; /** * Enabled SSL protocols. */ - private String[] enabledProtocols; + private String @Nullable [] enabledProtocols; /** * Alias that identifies the key in the key store. */ - private String keyAlias; + private @Nullable String keyAlias; /** * Password used to access the key in the key store. */ - private String keyPassword; + private @Nullable String keyPassword; /** * Path to the key store that holds the SSL certificate (typically a jks file). */ - private String keyStore; + private @Nullable String keyStore; /** * Password used to access the key store. */ - private String keyStorePassword; + private @Nullable String keyStorePassword; /** * Type of the key store. */ - private String keyStoreType; + private @Nullable String keyStoreType; /** * Provider for the key store. */ - private String keyStoreProvider; + private @Nullable String keyStoreProvider; /** * Trust store that holds SSL certificates. */ - private String trustStore; + private @Nullable String trustStore; /** * Password used to access the trust store. */ - private String trustStorePassword; + private @Nullable String trustStorePassword; /** * Type of the trust store. */ - private String trustStoreType; + private @Nullable String trustStoreType; /** * Provider for the trust store. */ - private String trustStoreProvider; + private @Nullable String trustStoreProvider; /** * Path to a PEM-encoded SSL certificate file. */ - private String certificate; + private @Nullable String certificate; /** * Path to a PEM-encoded private key file for the SSL certificate. */ - private String certificatePrivateKey; + private @Nullable String certificatePrivateKey; /** * Path to a PEM-encoded SSL certificate authority file. */ - private String trustCertificate; + private @Nullable String trustCertificate; /** * Path to a PEM-encoded private key file for the SSL certificate authority. */ - private String trustCertificatePrivateKey; + private @Nullable String trustCertificatePrivateKey; /** * SSL protocol to use. @@ -155,7 +158,7 @@ public class Ssl { * @return the SSL bundle name * @since 3.1.0 */ - public String getBundle() { + public @Nullable String getBundle() { return this.bundle; } @@ -164,7 +167,7 @@ public class Ssl { * @param bundle the SSL bundle name * @since 3.1.0 */ - public void setBundle(String bundle) { + public void setBundle(@Nullable String bundle) { this.bundle = bundle; } @@ -173,11 +176,11 @@ public class Ssl { * needed ("need"). Requires a trust store. * @return the {@link ClientAuth} to use */ - public ClientAuth getClientAuth() { + public @Nullable ClientAuth getClientAuth() { return this.clientAuth; } - public void setClientAuth(ClientAuth clientAuth) { + public void setClientAuth(@Nullable ClientAuth clientAuth) { this.clientAuth = clientAuth; } @@ -185,11 +188,11 @@ public class Ssl { * Return the supported SSL ciphers. * @return the supported SSL ciphers */ - public String[] getCiphers() { + public String @Nullable [] getCiphers() { return this.ciphers; } - public void setCiphers(String[] ciphers) { + public void setCiphers(String @Nullable [] ciphers) { this.ciphers = ciphers; } @@ -197,11 +200,11 @@ public class Ssl { * Return the enabled SSL protocols. * @return the enabled SSL protocols. */ - public String[] getEnabledProtocols() { + public String @Nullable [] getEnabledProtocols() { return this.enabledProtocols; } - public void setEnabledProtocols(String[] enabledProtocols) { + public void setEnabledProtocols(String @Nullable [] enabledProtocols) { this.enabledProtocols = enabledProtocols; } @@ -209,11 +212,11 @@ public class Ssl { * Return the alias that identifies the key in the key store. * @return the key alias */ - public String getKeyAlias() { + public @Nullable String getKeyAlias() { return this.keyAlias; } - public void setKeyAlias(String keyAlias) { + public void setKeyAlias(@Nullable String keyAlias) { this.keyAlias = keyAlias; } @@ -221,11 +224,11 @@ public class Ssl { * Return the password used to access the key in the key store. * @return the key password */ - public String getKeyPassword() { + public @Nullable String getKeyPassword() { return this.keyPassword; } - public void setKeyPassword(String keyPassword) { + public void setKeyPassword(@Nullable String keyPassword) { this.keyPassword = keyPassword; } @@ -234,11 +237,11 @@ public class Ssl { * file). * @return the path to the key store */ - public String getKeyStore() { + public @Nullable String getKeyStore() { return this.keyStore; } - public void setKeyStore(String keyStore) { + public void setKeyStore(@Nullable String keyStore) { this.keyStore = keyStore; } @@ -246,11 +249,11 @@ public class Ssl { * Return the password used to access the key store. * @return the key store password */ - public String getKeyStorePassword() { + public @Nullable String getKeyStorePassword() { return this.keyStorePassword; } - public void setKeyStorePassword(String keyStorePassword) { + public void setKeyStorePassword(@Nullable String keyStorePassword) { this.keyStorePassword = keyStorePassword; } @@ -258,11 +261,11 @@ public class Ssl { * Return the type of the key store. * @return the key store type */ - public String getKeyStoreType() { + public @Nullable String getKeyStoreType() { return this.keyStoreType; } - public void setKeyStoreType(String keyStoreType) { + public void setKeyStoreType(@Nullable String keyStoreType) { this.keyStoreType = keyStoreType; } @@ -270,11 +273,11 @@ public class Ssl { * Return the provider for the key store. * @return the key store provider */ - public String getKeyStoreProvider() { + public @Nullable String getKeyStoreProvider() { return this.keyStoreProvider; } - public void setKeyStoreProvider(String keyStoreProvider) { + public void setKeyStoreProvider(@Nullable String keyStoreProvider) { this.keyStoreProvider = keyStoreProvider; } @@ -282,11 +285,11 @@ public class Ssl { * Return the trust store that holds SSL certificates. * @return the trust store */ - public String getTrustStore() { + public @Nullable String getTrustStore() { return this.trustStore; } - public void setTrustStore(String trustStore) { + public void setTrustStore(@Nullable String trustStore) { this.trustStore = trustStore; } @@ -294,11 +297,11 @@ public class Ssl { * Return the password used to access the trust store. * @return the trust store password */ - public String getTrustStorePassword() { + public @Nullable String getTrustStorePassword() { return this.trustStorePassword; } - public void setTrustStorePassword(String trustStorePassword) { + public void setTrustStorePassword(@Nullable String trustStorePassword) { this.trustStorePassword = trustStorePassword; } @@ -306,11 +309,11 @@ public class Ssl { * Return the type of the trust store. * @return the trust store type */ - public String getTrustStoreType() { + public @Nullable String getTrustStoreType() { return this.trustStoreType; } - public void setTrustStoreType(String trustStoreType) { + public void setTrustStoreType(@Nullable String trustStoreType) { this.trustStoreType = trustStoreType; } @@ -318,11 +321,11 @@ public class Ssl { * Return the provider for the trust store. * @return the trust store provider */ - public String getTrustStoreProvider() { + public @Nullable String getTrustStoreProvider() { return this.trustStoreProvider; } - public void setTrustStoreProvider(String trustStoreProvider) { + public void setTrustStoreProvider(@Nullable String trustStoreProvider) { this.trustStoreProvider = trustStoreProvider; } @@ -330,11 +333,11 @@ public class Ssl { * Return the location of the certificate in PEM format. * @return the certificate location */ - public String getCertificate() { + public @Nullable String getCertificate() { return this.certificate; } - public void setCertificate(String certificate) { + public void setCertificate(@Nullable String certificate) { this.certificate = certificate; } @@ -342,11 +345,11 @@ public class Ssl { * Return the location of the private key for the certificate in PEM format. * @return the location of the certificate private key */ - public String getCertificatePrivateKey() { + public @Nullable String getCertificatePrivateKey() { return this.certificatePrivateKey; } - public void setCertificatePrivateKey(String certificatePrivateKey) { + public void setCertificatePrivateKey(@Nullable String certificatePrivateKey) { this.certificatePrivateKey = certificatePrivateKey; } @@ -354,11 +357,11 @@ public class Ssl { * Return the location of the trust certificate authority chain in PEM format. * @return the location of the trust certificate */ - public String getTrustCertificate() { + public @Nullable String getTrustCertificate() { return this.trustCertificate; } - public void setTrustCertificate(String trustCertificate) { + public void setTrustCertificate(@Nullable String trustCertificate) { this.trustCertificate = trustCertificate; } @@ -366,11 +369,11 @@ public class Ssl { * Return the location of the private key for the trust certificate in PEM format. * @return the location of the trust certificate private key */ - public String getTrustCertificatePrivateKey() { + public @Nullable String getTrustCertificatePrivateKey() { return this.trustCertificatePrivateKey; } - public void setTrustCertificatePrivateKey(String trustCertificatePrivateKey) { + public void setTrustCertificatePrivateKey(@Nullable String trustCertificatePrivateKey) { this.trustCertificatePrivateKey = trustCertificatePrivateKey; } @@ -392,7 +395,8 @@ public class Ssl { * @return {@code true} if SSL is enabled * @since 3.1.0 */ - public static boolean isEnabled(Ssl ssl) { + @Contract("null -> false") + public static boolean isEnabled(@Nullable Ssl ssl) { return (ssl != null) && ssl.isEnabled(); } @@ -453,7 +457,7 @@ public class Ssl { * @return the mapped value * @since 3.1.0 */ - public static R map(ClientAuth clientAuth, R none, R want, R need) { + public static @Nullable R map(@Nullable ClientAuth clientAuth, @Nullable R none, R want, R need) { return switch ((clientAuth != null) ? clientAuth : NONE) { case NONE -> none; case WANT -> want; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerException.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerException.java index d1a191c2839..30927a3c861 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerException.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerException.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server; +import org.jspecify.annotations.Nullable; + /** * Exceptions thrown by a web server. * @@ -25,7 +27,7 @@ package org.springframework.boot.web.server; @SuppressWarnings("serial") public class WebServerException extends RuntimeException { - public WebServerException(String message, Throwable cause) { + public WebServerException(String message, @Nullable Throwable cause) { super(message, cause); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java index 7698e8b1d6e..80b2bbc8b94 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java @@ -21,6 +21,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -41,9 +43,10 @@ import org.springframework.util.Assert; */ public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { + @SuppressWarnings("NullAway.Init") private ListableBeanFactory beanFactory; - private List> customizers; + private @Nullable List> customizers; @Override public void setBeanFactory(BeanFactory beanFactory) { diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java index d4abb474154..277c91fc260 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java @@ -18,6 +18,8 @@ package org.springframework.boot.web.server; import java.security.KeyStore; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.ssl.NoSuchSslBundleException; import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.ssl.SslBundleKey; @@ -52,7 +54,7 @@ public final class WebServerSslBundle implements SslBundle { private final SslManagerBundle managers; - private WebServerSslBundle(SslStoreBundle stores, String keyPassword, Ssl ssl) { + private WebServerSslBundle(SslStoreBundle stores, @Nullable String keyPassword, Ssl ssl) { this.stores = stores; this.key = SslBundleKey.of(keyPassword, ssl.getKeyAlias()); this.protocol = ssl.getProtocol(); @@ -129,7 +131,7 @@ public final class WebServerSslBundle implements SslBundle { * @return a {@link SslBundle} instance * @throws NoSuchSslBundleException if a bundle lookup fails */ - public static SslBundle get(Ssl ssl, SslBundles sslBundles) throws NoSuchSslBundleException { + public static SslBundle get(@Nullable Ssl ssl, @Nullable SslBundles sslBundles) throws NoSuchSslBundleException { Assert.state(Ssl.isEnabled(ssl), "SSL is not enabled"); String keyPassword = ssl.getKeyPassword(); String bundleName = ssl.getBundle(); @@ -149,7 +151,7 @@ public final class WebServerSslBundle implements SslBundle { return new WebServerSslStoreBundle(keyStore, trustStore, ssl.getKeyStorePassword()); } - private static KeyStore createKeyStore(Ssl ssl) { + private static @Nullable KeyStore createKeyStore(Ssl ssl) { if (hasPemKeyStoreProperties(ssl)) { return createPemKeyStoreBundle(ssl).getKeyStore(); } @@ -159,7 +161,7 @@ public final class WebServerSslBundle implements SslBundle { return null; } - private static KeyStore createTrustStore(Ssl ssl) { + private static @Nullable KeyStore createTrustStore(Ssl ssl) { if (hasPemTrustStoreProperties(ssl)) { return createPemTrustStoreBundle(ssl).getTrustStore(); } @@ -199,13 +201,14 @@ public final class WebServerSslBundle implements SslBundle { private static final class WebServerSslStoreBundle implements SslStoreBundle { - private final KeyStore keyStore; + private final @Nullable KeyStore keyStore; - private final KeyStore trustStore; + private final @Nullable KeyStore trustStore; - private final String keyStorePassword; + private final @Nullable String keyStorePassword; - private WebServerSslStoreBundle(KeyStore keyStore, KeyStore trustStore, String keyStorePassword) { + private WebServerSslStoreBundle(@Nullable KeyStore keyStore, @Nullable KeyStore trustStore, + @Nullable String keyStorePassword) { Assert.state(keyStore != null || trustStore != null, "SSL is enabled but no trust material is configured for the default host"); this.keyStore = keyStore; @@ -214,17 +217,17 @@ public final class WebServerSslBundle implements SslBundle { } @Override - public KeyStore getKeyStore() { + public @Nullable KeyStore getKeyStore() { return this.keyStore; } @Override - public KeyStore getTrustStore() { + public @Nullable KeyStore getTrustStore() { return this.trustStore; } @Override - public String getKeyStorePassword() { + public @Nullable String getKeyStorePassword() { return this.keyStorePassword; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/ServerProperties.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/ServerProperties.java index 518a9e36003..bc67f8463c2 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/ServerProperties.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/ServerProperties.java @@ -24,6 +24,8 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; @@ -74,12 +76,12 @@ public class ServerProperties { /** * Server HTTP port. */ - private Integer port; + private @Nullable Integer port; /** * Network address to which the server should bind. */ - private InetAddress address; + private @Nullable InetAddress address; @NestedConfigurationProperty private final ErrorProperties error = new ErrorProperties(); @@ -87,12 +89,12 @@ public class ServerProperties { /** * Strategy for handling X-Forwarded-* headers. */ - private ForwardHeadersStrategy forwardHeadersStrategy; + private @Nullable ForwardHeadersStrategy forwardHeadersStrategy; /** * Value to use for the Server response header (if empty, no header is sent). */ - private String serverHeader; + private @Nullable String serverHeader; /** * Maximum size of the HTTP request header. Refer to the documentation for your chosen @@ -109,7 +111,7 @@ public class ServerProperties { private Shutdown shutdown = Shutdown.GRACEFUL; @NestedConfigurationProperty - private Ssl ssl; + private @Nullable Ssl ssl; @NestedConfigurationProperty private final Compression compression = new Compression(); @@ -126,27 +128,27 @@ public class ServerProperties { private final Reactive reactive = new Reactive(); - public Integer getPort() { + public @Nullable Integer getPort() { return this.port; } - public void setPort(Integer port) { + public void setPort(@Nullable Integer port) { this.port = port; } - public InetAddress getAddress() { + public @Nullable InetAddress getAddress() { return this.address; } - public void setAddress(InetAddress address) { + public void setAddress(@Nullable InetAddress address) { this.address = address; } - public String getServerHeader() { + public @Nullable String getServerHeader() { return this.serverHeader; } - public void setServerHeader(String serverHeader) { + public void setServerHeader(@Nullable String serverHeader) { this.serverHeader = serverHeader; } @@ -170,11 +172,11 @@ public class ServerProperties { return this.error; } - public Ssl getSsl() { + public @Nullable Ssl getSsl() { return this.ssl; } - public void setSsl(Ssl ssl) { + public void setSsl(@Nullable Ssl ssl) { this.ssl = ssl; } @@ -202,11 +204,11 @@ public class ServerProperties { return this.reactive; } - public ForwardHeadersStrategy getForwardHeadersStrategy() { + public @Nullable ForwardHeadersStrategy getForwardHeadersStrategy() { return this.forwardHeadersStrategy; } - public void setForwardHeadersStrategy(ForwardHeadersStrategy forwardHeadersStrategy) { + public void setForwardHeadersStrategy(@Nullable ForwardHeadersStrategy forwardHeadersStrategy) { this.forwardHeadersStrategy = forwardHeadersStrategy; } @@ -223,7 +225,7 @@ public class ServerProperties { /** * Context path of the application. */ - private String contextPath; + private @Nullable String contextPath; /** * Display name of the application. @@ -243,15 +245,15 @@ public class ServerProperties { @NestedConfigurationProperty private final Session session = new Session(); - public String getContextPath() { + public @Nullable String getContextPath() { return this.contextPath; } - public void setContextPath(String contextPath) { + public void setContextPath(@Nullable String contextPath) { this.contextPath = cleanContextPath(contextPath); } - private String cleanContextPath(String contextPath) { + private @Nullable String cleanContextPath(@Nullable String contextPath) { String candidate = null; if (StringUtils.hasLength(contextPath)) { candidate = contextPath.strip(); @@ -375,13 +377,13 @@ public class ServerProperties { /** * Mapping of locale to charset for response encoding. */ - private Map mapping; + private @Nullable Map mapping; - public Map getMapping() { + public @Nullable Map getMapping() { return this.mapping; } - public void setMapping(Map mapping) { + public void setMapping(@Nullable Map mapping) { this.mapping = mapping; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/package-info.java index 13a8a376f6b..6bb565b205d 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/package-info.java @@ -17,4 +17,7 @@ /** * Classes related to the auto-configuration of a web server. */ +@NullMarked package org.springframework.boot.web.server.autoconfigure; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerConfiguration.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerConfiguration.java index 7dd622f3869..45d50cdf0a8 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerConfiguration.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.autoconfigure.reactive; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -68,7 +70,7 @@ public class ReactiveWebServerConfiguration { */ public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { - private ConfigurableListableBeanFactory beanFactory; + private @Nullable ConfigurableListableBeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { @@ -83,13 +85,13 @@ public class ReactiveWebServerConfiguration { if (this.beanFactory == null) { return; } - registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", + registerSyntheticBeanIfMissing(this.beanFactory, registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); } - private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, - Class beanClass) { - if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { + private void registerSyntheticBeanIfMissing(ConfigurableListableBeanFactory beanFactory, + BeanDefinitionRegistry registry, String name, Class beanClass) { + if (ObjectUtils.isEmpty(beanFactory.getBeanNamesForType(beanClass, true, false))) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizer.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizer.java index cbd0a4f67e7..ca30f4ec9c9 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizer.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizer.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.autoconfigure.reactive; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -37,7 +39,7 @@ public class ReactiveWebServerFactoryCustomizer private final ServerProperties serverProperties; - private final SslBundles sslBundles; + private final @Nullable SslBundles sslBundles; /** * Create a new {@link ReactiveWebServerFactoryCustomizer} instance. @@ -53,7 +55,7 @@ public class ReactiveWebServerFactoryCustomizer * @param sslBundles the SSL bundles * @since 4.0.0 */ - public ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties, SslBundles sslBundles) { + public ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties, @Nullable SslBundles sslBundles) { this.serverProperties = serverProperties; this.sslBundles = sslBundles; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/package-info.java index f70ff6a6cc2..76d4af538b5 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/package-info.java @@ -17,4 +17,7 @@ /** * Classes related to the auto-configuration of a reactive web server. */ +@NullMarked package org.springframework.boot.web.server.autoconfigure.reactive; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerConfiguration.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerConfiguration.java index 79aea0a6654..088f134ace4 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerConfiguration.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.boot.web.server.autoconfigure.servlet; import jakarta.servlet.DispatcherType; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -87,7 +88,7 @@ public class ServletWebServerConfiguration { */ static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { - private ConfigurableListableBeanFactory beanFactory; + private @Nullable ConfigurableListableBeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { @@ -102,15 +103,15 @@ public class ServletWebServerConfiguration { if (this.beanFactory == null) { return; } - registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", + registerSyntheticBeanIfMissing(this.beanFactory, registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); - registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", + registerSyntheticBeanIfMissing(this.beanFactory, registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class); } - private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, - Class beanClass) { - if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { + private void registerSyntheticBeanIfMissing(ConfigurableListableBeanFactory beanFactory, + BeanDefinitionRegistry registry, String name, Class beanClass) { + if (ObjectUtils.isEmpty(beanFactory.getBeanNamesForType(beanClass, true, false))) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizer.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizer.java index 7da8fd14ceb..861ef243638 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizer.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizer.java @@ -19,6 +19,8 @@ package org.springframework.boot.web.server.autoconfigure.servlet; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -50,7 +52,7 @@ public class ServletWebServerFactoryCustomizer private final List cookieSameSiteSuppliers; - private final SslBundles sslBundles; + private final @Nullable SslBundles sslBundles; public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) { this(serverProperties, Collections.emptyList(), Collections.emptyList(), null); @@ -58,7 +60,7 @@ public class ServletWebServerFactoryCustomizer public ServletWebServerFactoryCustomizer(ServerProperties serverProperties, List webListenerRegistrars, List cookieSameSiteSuppliers, - SslBundles sslBundles) { + @Nullable SslBundles sslBundles) { this.serverProperties = serverProperties; this.webListenerRegistrars = webListenerRegistrars; this.cookieSameSiteSuppliers = cookieSameSiteSuppliers; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/package-info.java index 6514d77336c..1b7269bf2b5 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/package-info.java @@ -17,4 +17,7 @@ /** * Classes related to the auto-configuration of a servlet web server. */ +@NullMarked package org.springframework.boot.web.server.autoconfigure.servlet; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ConfigurableWebServerApplicationContext.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ConfigurableWebServerApplicationContext.java index d88d5ba6df7..26e00b71a6a 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ConfigurableWebServerApplicationContext.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ConfigurableWebServerApplicationContext.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.context; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ConfigurableApplicationContext; /** @@ -34,6 +36,6 @@ public interface ConfigurableWebServerApplicationContext * @param serverNamespace the server namespace * @see #getServerNamespace() */ - void setServerNamespace(String serverNamespace); + void setServerNamespace(@Nullable String serverNamespace); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java index 24fe16a3f9a..379f3fb84d1 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java @@ -22,6 +22,7 @@ import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalyzer; import org.springframework.core.annotation.Order; +import org.springframework.util.Assert; /** * A {@link FailureAnalyzer} that performs analysis of failures caused by a @@ -35,8 +36,10 @@ class MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer @Override protected FailureAnalysis analyze(Throwable rootFailure, MissingWebServerFactoryBeanException cause) { + Class beanType = cause.getBeanType(); + Assert.state(beanType != null, "'beanType' must not be null"); return new FailureAnalysis( - "Web application could not be started as there was no " + cause.getBeanType().getName() + "Web application could not be started as there was no " + beanType.getName() + " bean defined in the context.", "Check your application's dependencies for a supported " + cause.getWebApplicationType().name().toLowerCase(Locale.ENGLISH) + " web server.\n" diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerApplicationContext.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerApplicationContext.java index dce6dd9940c..16c6a953538 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerApplicationContext.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerApplicationContext.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.context; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.web.server.WebServer; import org.springframework.context.ApplicationContext; import org.springframework.context.SmartLifecycle; @@ -49,7 +51,7 @@ public interface WebServerApplicationContext extends ApplicationContext { * the server has not yet been created. * @return the web server */ - WebServer getWebServer(); + @Nullable WebServer getWebServer(); /** * Returns the namespace of the web server application context or {@code null} if no @@ -58,7 +60,7 @@ public interface WebServerApplicationContext extends ApplicationContext { * different port). * @return the server namespace */ - String getServerNamespace(); + @Nullable String getServerNamespace(); /** * Returns {@code true} if the specified context is a @@ -81,7 +83,7 @@ public interface WebServerApplicationContext extends ApplicationContext { * {@link WebServerApplicationContext} * @since 2.6.0 */ - static String getServerNamespace(ApplicationContext context) { + static @Nullable String getServerNamespace(ApplicationContext context) { return (context instanceof WebServerApplicationContext configurableContext) ? configurableContext.getServerNamespace() : null; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerPortFileWriter.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerPortFileWriter.java index 0a37fcbca47..d88140663fd 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerPortFileWriter.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerPortFileWriter.java @@ -21,6 +21,7 @@ import java.util.Locale; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.boot.system.SystemProperties; import org.springframework.context.ApplicationContext; @@ -118,7 +119,7 @@ public class WebServerPortFileWriter implements ApplicationListener> annotatedClasses = new LinkedHashSet<>(); - private String[] basePackages; + private String @Nullable [] basePackages; /** * Create a new {@link AnnotationConfigReactiveWebServerApplicationContext} that needs diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironment.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironment.java index a40314d58c8..4554bb43e0c 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironment.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironment.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.reactive.context; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.SpringApplication; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.web.context.reactive.StandardReactiveWebEnvironment; @@ -31,12 +33,12 @@ import org.springframework.core.env.MutablePropertySources; class ApplicationReactiveWebEnvironment extends StandardReactiveWebEnvironment { @Override - protected String doGetActiveProfilesProperty() { + protected @Nullable String doGetActiveProfilesProperty() { return null; } @Override - protected String doGetDefaultProfilesProperty() { + protected @Nullable String doGetDefaultProfilesProperty() { return null; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContext.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContext.java index 42de45cea0c..3357322db31 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContext.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContext.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.reactive.context; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.WebApplicationType; @@ -42,9 +44,9 @@ import org.springframework.util.StringUtils; public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext implements ConfigurableWebServerApplicationContext { - private volatile WebServerManager serverManager; + private volatile @Nullable WebServerManager serverManager; - private String serverNamespace; + private @Nullable String serverNamespace; /** * Create a new {@link ReactiveWebServerApplicationContext}. @@ -166,18 +168,18 @@ public class ReactiveWebServerApplicationContext extends GenericReactiveWebAppli * @return the web server */ @Override - public WebServer getWebServer() { + public @Nullable WebServer getWebServer() { WebServerManager serverManager = this.serverManager; return (serverManager != null) ? serverManager.getWebServer() : null; } @Override - public String getServerNamespace() { + public @Nullable String getServerNamespace() { return this.serverNamespace; } @Override - public void setServerNamespace(String serverNamespace) { + public void setServerNamespace(@Nullable String serverNamespace) { this.serverNamespace = serverNamespace; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextFactory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextFactory.java index 4ae2871be66..1337e558388 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextFactory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextFactory.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.reactive.context; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.AotDetector; import org.springframework.boot.ApplicationContextFactory; import org.springframework.boot.WebApplicationType; @@ -33,17 +35,18 @@ import org.springframework.core.env.ConfigurableEnvironment; class ReactiveWebServerApplicationContextFactory implements ApplicationContextFactory { @Override - public Class getEnvironmentType(WebApplicationType webApplicationType) { + public @Nullable Class getEnvironmentType( + @Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.REACTIVE) ? null : ApplicationReactiveWebEnvironment.class; } @Override - public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) { + public @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.REACTIVE) ? null : new ApplicationReactiveWebEnvironment(); } @Override - public ConfigurableApplicationContext create(WebApplicationType webApplicationType) { + public @Nullable ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.REACTIVE) ? null : createContext(); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/package-info.java index 3c765592ebd..348acbab459 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/package-info.java @@ -18,4 +18,7 @@ * Reactive web server based integrations with Spring's * {@link org.springframework.context.ApplicationContext ApplicationContext}. */ +@NullMarked package org.springframework.boot.web.server.reactive.context; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/package-info.java index 4419bc5cdc3..35c3d56f6f0 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/package-info.java @@ -17,4 +17,7 @@ /** * Reactive web server abstractions. */ +@NullMarked package org.springframework.boot.web.server.reactive; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ConfigurableServletWebServerFactory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ConfigurableServletWebServerFactory.java index 1911b3d911b..3cf9142f711 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ConfigurableServletWebServerFactory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ConfigurableServletWebServerFactory.java @@ -23,6 +23,7 @@ import java.util.Locale; import java.util.Map; import jakarta.servlet.ServletContext; +import org.jspecify.annotations.Nullable; import org.springframework.boot.web.server.ConfigurableWebServerFactory; import org.springframework.boot.web.server.Cookie.SameSite; @@ -115,7 +116,7 @@ public interface ConfigurableServletWebServerFactory * static files. * @param documentRoot the document root or {@code null} if not required */ - default void setDocumentRoot(File documentRoot) { + default void setDocumentRoot(@Nullable File documentRoot) { getSettings().setDocumentRoot(documentRoot); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java index 1a97f47923f..06cc05a1267 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java @@ -21,6 +21,7 @@ import java.util.function.Supplier; import java.util.regex.Pattern; import jakarta.servlet.http.Cookie; +import org.jspecify.annotations.Nullable; import org.springframework.boot.web.server.Cookie.SameSite; import org.springframework.util.Assert; @@ -49,7 +50,7 @@ public interface CookieSameSiteSupplier { * @return the {@link SameSite} value to use or {@code null} if the next supplier * should be checked */ - SameSite getSameSite(Cookie cookie); + @Nullable SameSite getSameSite(Cookie cookie); /** * Limit this supplier so that it's only called if the Cookie has the given name. diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/DocumentRoot.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/DocumentRoot.java index 34afe526daa..18ba6be49c4 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/DocumentRoot.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/DocumentRoot.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Locale; import org.apache.commons.logging.Log; +import org.jspecify.annotations.Nullable; /** * Manages a {@link ServletWebServerFactory} document root. @@ -38,17 +39,17 @@ public class DocumentRoot { private final Log logger; - private File directory; + private @Nullable File directory; public DocumentRoot(Log logger) { this.logger = logger; } - File getDirectory() { + @Nullable File getDirectory() { return this.directory; } - public void setDirectory(File directory) { + public void setDirectory(@Nullable File directory) { this.directory = directory; } @@ -57,7 +58,7 @@ public class DocumentRoot { * warning and returning {@code null} otherwise. * @return the valid document root */ - public final File getValidDirectory() { + public final @Nullable File getValidDirectory() { File file = this.directory; file = (file != null) ? file : getWarFileDocumentRoot(); file = (file != null) ? file : getExplodedWarFileDocumentRoot(); @@ -71,11 +72,11 @@ public class DocumentRoot { return file; } - private File getWarFileDocumentRoot() { + private @Nullable File getWarFileDocumentRoot() { return getArchiveFileDocumentRoot(".war"); } - private File getArchiveFileDocumentRoot(String extension) { + private @Nullable File getArchiveFileDocumentRoot(String extension) { File file = getCodeSourceArchive(); if (this.logger.isDebugEnabled()) { this.logger.debug("Code archive: " + file); @@ -87,15 +88,15 @@ public class DocumentRoot { return null; } - private File getExplodedWarFileDocumentRoot() { + private @Nullable File getExplodedWarFileDocumentRoot() { return getExplodedWarFileDocumentRoot(getCodeSourceArchive()); } - private File getCodeSourceArchive() { + private @Nullable File getCodeSourceArchive() { return getCodeSourceArchive(getClass().getProtectionDomain().getCodeSource()); } - File getCodeSourceArchive(CodeSource codeSource) { + @Nullable File getCodeSourceArchive(@Nullable CodeSource codeSource) { try { URL location = (codeSource != null) ? codeSource.getLocation() : null; if (location == null) { @@ -120,7 +121,7 @@ public class DocumentRoot { } } - final File getExplodedWarFileDocumentRoot(File codeSourceFile) { + final @Nullable File getExplodedWarFileDocumentRoot(@Nullable File codeSourceFile) { if (this.logger.isDebugEnabled()) { this.logger.debug("Code archive: " + codeSourceFile); } @@ -135,7 +136,7 @@ public class DocumentRoot { return null; } - private File getCommonDocumentRoot() { + private @Nullable File getCommonDocumentRoot() { for (String commonDocRoot : COMMON_DOC_ROOTS) { File root = new File(commonDocRoot); if (root.exists() && root.isDirectory()) { diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletContextInitializers.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletContextInitializers.java index de014088808..31dfdf0e7f1 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletContextInitializers.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletContextInitializers.java @@ -27,11 +27,13 @@ import java.util.Set; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.SessionCookieConfig; +import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.web.server.Cookie; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.lang.Contract; /** * The {@link ServletContextInitializer ServletContextInitializers} to apply to a servlet @@ -100,7 +102,9 @@ public final class ServletContextInitializers implements Iterable config.setAttribute("Partitioned", partitioned)); } - private Set unwrap(Set modes) { + @Contract("!null -> !null") + private @Nullable Set unwrap( + @Nullable Set modes) { if (modes == null) { return null; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerSettings.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerSettings.java index 11f9a53b132..977404f329a 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerSettings.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerSettings.java @@ -28,6 +28,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.web.server.MimeMappings; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.servlet.ServletContextInitializer; @@ -44,7 +46,7 @@ public class ServletWebServerSettings { private ContextPath contextPath = ContextPath.DEFAULT; - private String displayName; + private @Nullable String displayName; private Session session = new Session(); @@ -52,7 +54,7 @@ public class ServletWebServerSettings { private MimeMappings mimeMappings = MimeMappings.lazyCopy(MimeMappings.DEFAULT); - private File documentRoot; + private @Nullable File documentRoot; private List initializers = new ArrayList<>(); @@ -76,11 +78,11 @@ public class ServletWebServerSettings { this.contextPath = contextPath; } - public String getDisplayName() { + public @Nullable String getDisplayName() { return this.displayName; } - public void setDisplayName(String displayName) { + public void setDisplayName(@Nullable String displayName) { this.displayName = displayName; } @@ -104,11 +106,11 @@ public class ServletWebServerSettings { return this.mimeMappings; } - public File getDocumentRoot() { + public @Nullable File getDocumentRoot() { return this.documentRoot; } - public void setDocumentRoot(File documentRoot) { + public void setDocumentRoot(@Nullable File documentRoot) { this.documentRoot = documentRoot; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Session.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Session.java index d208c59e1c2..b2c3477143c 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Session.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Session.java @@ -21,6 +21,8 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.context.properties.ConfigurationPropertiesSource; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.convert.DurationUnit; @@ -44,7 +46,7 @@ public class Session { /** * Session tracking modes. */ - private Set trackingModes; + private @Nullable Set trackingModes; /** * Whether to persist session data between restarts. @@ -54,7 +56,7 @@ public class Session { /** * Directory used to store session data. */ - private File storeDir; + private @Nullable File storeDir; @NestedConfigurationProperty private final Cookie cookie = new Cookie(); @@ -73,11 +75,11 @@ public class Session { * Return the {@link SessionTrackingMode session tracking modes}. * @return the session tracking modes */ - public Set getTrackingModes() { + public @Nullable Set getTrackingModes() { return this.trackingModes; } - public void setTrackingModes(Set trackingModes) { + public void setTrackingModes(@Nullable Set trackingModes) { this.trackingModes = trackingModes; } @@ -97,11 +99,11 @@ public class Session { * Return the directory used to store session data. * @return the session data store directory */ - public File getStoreDir() { + public @Nullable File getStoreDir() { return this.storeDir; } - public void setStoreDir(File storeDir) { + public void setStoreDir(@Nullable File storeDir) { this.sessionStoreDirectory.setDirectory(storeDir); this.storeDir = storeDir; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/SessionStoreDirectory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/SessionStoreDirectory.java index 7d37866b61a..de45231ae76 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/SessionStoreDirectory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/SessionStoreDirectory.java @@ -18,6 +18,8 @@ package org.springframework.boot.web.server.servlet; import java.io.File; +import org.jspecify.annotations.Nullable; + import org.springframework.boot.system.ApplicationHome; import org.springframework.boot.system.ApplicationTemp; import org.springframework.util.Assert; @@ -30,13 +32,13 @@ import org.springframework.util.Assert; */ public class SessionStoreDirectory { - private File directory; + private @Nullable File directory; - File getDirectory() { + @Nullable File getDirectory() { return this.directory; } - void setDirectory(File directory) { + void setDirectory(@Nullable File directory) { this.directory = directory; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/StaticResourceJars.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/StaticResourceJars.java index db422233620..e986d22c51a 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/StaticResourceJars.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/StaticResourceJars.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.jar.JarFile; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + /** * Logic to extract URLs of static resource jars (those containing * {@code "META-INF/resources"} directories). @@ -69,7 +71,7 @@ class StaticResourceJars { } } - private File toFile(URL url) { + private @Nullable File toFile(URL url) { try { return new File(url.toURI()); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContext.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContext.java index 18b29babe18..7c3969e62f6 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContext.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContext.java @@ -20,6 +20,8 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -61,7 +63,7 @@ public class AnnotationConfigServletWebServerApplicationContext extends ServletW private final Set> annotatedClasses = new LinkedHashSet<>(); - private String[] basePackages; + private String @Nullable [] basePackages; /** * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentHandler.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentHandler.java index f604e3f9dc5..f48acb66076 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentHandler.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentHandler.java @@ -20,6 +20,8 @@ import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; @@ -48,9 +50,11 @@ abstract class ServletComponentHandler { return this.typeFilter; } - protected String[] extractUrlPatterns(Map attributes) { + protected String[] extractUrlPatterns(Map attributes) { String[] value = (String[]) attributes.get("value"); String[] urlPatterns = (String[]) attributes.get("urlPatterns"); + Assert.state(urlPatterns != null, "'urlPatterns' must not be null"); + Assert.state(value != null, "'value' must not be null"); if (urlPatterns.length > 0) { Assert.state(value.length == 0, "The urlPatterns and value attributes are mutually exclusive"); return urlPatterns; @@ -58,25 +62,29 @@ abstract class ServletComponentHandler { return value; } - protected final Map extractInitParameters(Map attributes) { + protected final Map extractInitParameters(Map attributes) { Map initParameters = new HashMap<>(); - for (AnnotationAttributes initParam : (AnnotationAttributes[]) attributes.get("initParams")) { + AnnotationAttributes[] initParams = (AnnotationAttributes[]) attributes.get("initParams"); + Assert.state(initParams != null, "'initParams' must not be null"); + for (AnnotationAttributes initParam : initParams) { String name = (String) initParam.get("name"); String value = (String) initParam.get("value"); + Assert.state(name != null, "'name' must not be null"); + Assert.state(value != null, "'value' must not be null"); initParameters.put(name, value); } return initParameters; } void handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) { - Map attributes = beanDefinition.getMetadata() + Map attributes = beanDefinition.getMetadata() .getAnnotationAttributes(this.annotationType.getName()); if (attributes != null) { doHandle(attributes, beanDefinition, registry); } } - protected abstract void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, + protected abstract void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentRegisteringPostProcessor.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentRegisteringPostProcessor.java index ef31f241eb1..88ef7b242f6 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentRegisteringPostProcessor.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentRegisteringPostProcessor.java @@ -31,11 +31,13 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcess import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.mock.web.MockServletContext; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.web.context.WebApplicationContext; @@ -65,6 +67,7 @@ class ServletComponentRegisteringPostProcessor private final Set packagesToScan; + @SuppressWarnings("NullAway.Init") private ApplicationContext applicationContext; ServletComponentRegisteringPostProcessor(Set packagesToScan) { @@ -124,9 +127,11 @@ class ServletComponentRegisteringPostProcessor BeanDefinition definition = beanFactory.getBeanDefinition(beanName); if (Objects.equals(definition.getBeanClassName(), WebListenerHandler.ServletComponentWebListenerRegistrar.class.getName())) { - String listenerClassName = (String) definition.getConstructorArgumentValues() - .getArgumentValue(0, String.class) - .getValue(); + ValueHolder firstArgument = definition.getConstructorArgumentValues() + .getArgumentValue(0, String.class); + Assert.notNull(firstArgument, "'firstArgument' must not be null"); + String listenerClassName = (String) firstArgument.getValue(); + Assert.state(listenerClassName != null, "'listenerClassName' must not be null"); generationContext.getRuntimeHints() .reflection() .registerType(TypeReference.of(listenerClassName), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrar.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrar.java index b23155b22b9..405a17e8cfe 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrar.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrar.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** @@ -67,6 +68,7 @@ class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar { private Set getPackagesToScan(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(ServletComponentScan.class.getName())); + Assert.state(attributes != null, "'attributes' must not be null"); String[] basePackages = attributes.getStringArray("basePackages"); Class[] basePackageClasses = attributes.getClassArray("basePackageClasses"); Set packagesToScan = new LinkedHashSet<>(Arrays.asList(basePackages)); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContext.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContext.java index c2f740b0c6f..87c6290570f 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContext.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContext.java @@ -29,6 +29,7 @@ import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -104,11 +105,11 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon */ public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet"; - private volatile WebServer webServer; + private volatile @Nullable WebServer webServer; - private ServletConfig servletConfig; + private @Nullable ServletConfig servletConfig; - private String serverNamespace; + private @Nullable String serverNamespace; /** * Create a new {@link ServletWebServerApplicationContext}. @@ -249,22 +250,22 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon } @Override - public String getServerNamespace() { + public @Nullable String getServerNamespace() { return this.serverNamespace; } @Override - public void setServerNamespace(String serverNamespace) { + public void setServerNamespace(@Nullable String serverNamespace) { this.serverNamespace = serverNamespace; } @Override - public void setServletConfig(ServletConfig servletConfig) { + public void setServletConfig(@Nullable ServletConfig servletConfig) { this.servletConfig = servletConfig; } @Override - public ServletConfig getServletConfig() { + public @Nullable ServletConfig getServletConfig() { return this.servletConfig; } @@ -274,7 +275,7 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon * @return the embedded web server */ @Override - public WebServer getWebServer() { + public @Nullable WebServer getWebServer() { return this.webServer; } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextFactory.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextFactory.java index 73337e94fff..821c988ca71 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextFactory.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextFactory.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server.servlet.context; +import org.jspecify.annotations.Nullable; + import org.springframework.aot.AotDetector; import org.springframework.boot.ApplicationContextFactory; import org.springframework.boot.WebApplicationType; @@ -34,17 +36,18 @@ import org.springframework.core.env.ConfigurableEnvironment; class ServletWebServerApplicationContextFactory implements ApplicationContextFactory { @Override - public Class getEnvironmentType(WebApplicationType webApplicationType) { + public @Nullable Class getEnvironmentType( + @Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.SERVLET) ? null : ApplicationServletEnvironment.class; } @Override - public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) { + public @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.SERVLET) ? null : new ApplicationServletEnvironment(); } @Override - public ConfigurableApplicationContext create(WebApplicationType webApplicationType) { + public @Nullable ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) { return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext(); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebApplicationContextServletContextAwareProcessor.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebApplicationContextServletContextAwareProcessor.java index ec4d3ac2070..22949175b9a 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebApplicationContextServletContextAwareProcessor.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebApplicationContextServletContextAwareProcessor.java @@ -18,6 +18,7 @@ package org.springframework.boot.web.server.servlet.context; import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.web.context.ConfigurableWebApplicationContext; @@ -42,13 +43,13 @@ public class WebApplicationContextServletContextAwareProcessor extends ServletCo } @Override - protected ServletContext getServletContext() { + protected @Nullable ServletContext getServletContext() { ServletContext servletContext = this.webApplicationContext.getServletContext(); return (servletContext != null) ? servletContext : super.getServletContext(); } @Override - protected ServletConfig getServletConfig() { + protected @Nullable ServletConfig getServletConfig() { ServletConfig servletConfig = this.webApplicationContext.getServletConfig(); return (servletConfig != null) ? servletConfig : super.getServletConfig(); } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebFilterHandler.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebFilterHandler.java index 2f54314693c..7e00ff80bab 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebFilterHandler.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebFilterHandler.java @@ -22,12 +22,14 @@ import java.util.Map; import jakarta.servlet.DispatcherType; import jakarta.servlet.annotation.WebFilter; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -42,7 +44,7 @@ class WebFilterHandler extends ServletComponentHandler { } @Override - public void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, + public void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class); builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported")); @@ -56,8 +58,9 @@ class WebFilterHandler extends ServletComponentHandler { registry.registerBeanDefinition(name, builder.getBeanDefinition()); } - private EnumSet extractDispatcherTypes(Map attributes) { + private EnumSet extractDispatcherTypes(Map attributes) { DispatcherType[] dispatcherTypes = (DispatcherType[]) attributes.get("dispatcherTypes"); + Assert.state(dispatcherTypes != null, "'dispatcherTypes' must not be null"); if (dispatcherTypes.length == 0) { return EnumSet.noneOf(DispatcherType.class); } @@ -67,9 +70,15 @@ class WebFilterHandler extends ServletComponentHandler { return EnumSet.of(dispatcherTypes[0], Arrays.copyOfRange(dispatcherTypes, 1, dispatcherTypes.length)); } - private String determineName(Map attributes, BeanDefinition beanDefinition) { - return (String) (StringUtils.hasText((String) attributes.get("filterName")) ? attributes.get("filterName") - : beanDefinition.getBeanClassName()); + private String determineName(Map attributes, BeanDefinition beanDefinition) { + String filterName = (String) attributes.get("filterName"); + return (StringUtils.hasText(filterName) ? filterName : getBeanClassName(beanDefinition)); + } + + private String getBeanClassName(BeanDefinition beanDefinition) { + String name = beanDefinition.getBeanClassName(); + Assert.state(name != null, "'name' must not be null"); + return name; } } diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebListenerHandler.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebListenerHandler.java index 736a19c4f40..f51650d0517 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebListenerHandler.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebListenerHandler.java @@ -19,6 +19,7 @@ package org.springframework.boot.web.server.servlet.context; import java.util.Map; import jakarta.servlet.annotation.WebListener; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -38,7 +39,7 @@ class WebListenerHandler extends ServletComponentHandler { } @Override - protected void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, + protected void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .rootBeanDefinition(ServletComponentWebListenerRegistrar.class); diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServletHandler.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServletHandler.java index 5d75368fc81..3e12fe7fccc 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServletHandler.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServletHandler.java @@ -21,12 +21,14 @@ import java.util.Map; import jakarta.servlet.MultipartConfigElement; import jakarta.servlet.annotation.MultipartConfig; import jakarta.servlet.annotation.WebServlet; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -41,7 +43,7 @@ class WebServletHandler extends ServletComponentHandler { } @Override - public void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, + public void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletRegistrationBean.class); builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported")); @@ -55,13 +57,19 @@ class WebServletHandler extends ServletComponentHandler { registry.registerBeanDefinition(name, builder.getBeanDefinition()); } - private String determineName(Map attributes, BeanDefinition beanDefinition) { - return (String) (StringUtils.hasText((String) attributes.get("name")) ? attributes.get("name") - : beanDefinition.getBeanClassName()); + private String determineName(Map attributes, BeanDefinition beanDefinition) { + String name = (String) attributes.get("name"); + return StringUtils.hasText(name) ? name : getBeanClassName(beanDefinition); } - private BeanDefinition determineMultipartConfig(AnnotatedBeanDefinition beanDefinition) { - Map attributes = beanDefinition.getMetadata() + private String getBeanClassName(BeanDefinition beanDefinition) { + String name = beanDefinition.getBeanClassName(); + Assert.state(name != null, "'name' must not be null"); + return name; + } + + private @Nullable BeanDefinition determineMultipartConfig(AnnotatedBeanDefinition beanDefinition) { + Map attributes = beanDefinition.getMetadata() .getAnnotationAttributes(MultipartConfig.class.getName()); if (attributes == null) { return null; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/package-info.java index e8602ac718c..afe159b167e 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/package-info.java @@ -18,4 +18,7 @@ * Servlet web server based web integrations with Spring's * {@link org.springframework.web.context.WebApplicationContext WebApplicationContext}. */ +@NullMarked package org.springframework.boot.web.server.servlet.context; + +import org.jspecify.annotations.NullMarked; diff --git a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/package-info.java b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/package-info.java index a794e4b1fbf..0f2140e5528 100644 --- a/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/package-info.java +++ b/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/package-info.java @@ -17,4 +17,7 @@ /** * Servlet web server abstractions. */ +@NullMarked package org.springframework.boot.web.server.servlet; + +import org.jspecify.annotations.NullMarked;