Browse Source

Add nullability annotations to module/spring-boot-undertow

See gh-46587
pull/47390/head
Moritz Halbritter 7 months ago
parent
commit
e327eb7b45
  1. 19
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/AccessLogHttpHandlerFactory.java
  2. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/CompressionHttpHandlerFactory.java
  3. 17
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/ConfigurableUndertowWebServerFactory.java
  4. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/HttpHandlerFactory.java
  5. 7
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/SslBuilderCustomizer.java
  6. 75
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServer.java
  7. 41
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServerFactory.java
  8. 37
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowServerProperties.java
  9. 6
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowAccessLogCustomizer.java
  10. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/package-info.java
  11. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/package-info.java
  12. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/package-info.java
  13. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/package-info.java
  14. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/package-info.java
  15. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/package-info.java
  16. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/CompositeResourceManager.java
  17. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/DeploymentManagerHttpHandlerFactory.java
  18. 4
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/FileSessionPersistence.java
  19. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/JarResourceManager.java
  20. 9
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServer.java
  21. 30
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactory.java
  22. 3
      module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/package-info.java

19
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/AccessLogHttpHandlerFactory.java

@ -25,13 +25,12 @@ import io.undertow.Undertow;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.accesslog.AccessLogHandler; import io.undertow.server.handlers.accesslog.AccessLogHandler;
import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver; import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver;
import org.jspecify.annotations.Nullable;
import org.xnio.OptionMap; import org.xnio.OptionMap;
import org.xnio.Options; import org.xnio.Options;
import org.xnio.Xnio; import org.xnio.Xnio;
import org.xnio.XnioWorker; import org.xnio.XnioWorker;
import org.springframework.util.Assert;
/** /**
* An {@link HttpHandlerFactory} for an {@link AccessLogHandler}. * An {@link HttpHandlerFactory} for an {@link AccessLogHandler}.
* *
@ -41,15 +40,16 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
private final File directory; private final File directory;
private final String pattern; private final @Nullable String pattern;
private final String prefix; private final @Nullable String prefix;
private final String suffix; private final @Nullable String suffix;
private final boolean rotate; private final boolean rotate;
AccessLogHttpHandlerFactory(File directory, String pattern, String prefix, String suffix, boolean rotate) { AccessLogHttpHandlerFactory(File directory, @Nullable String pattern, @Nullable String prefix,
@Nullable String suffix, boolean rotate) {
this.directory = directory; this.directory = directory;
this.pattern = pattern; this.pattern = pattern;
this.prefix = prefix; this.prefix = prefix;
@ -58,7 +58,7 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
} }
@Override @Override
public HttpHandler getHandler(HttpHandler next) { public HttpHandler getHandler(@Nullable HttpHandler next) {
try { try {
createAccessLogDirectoryIfNecessary(); createAccessLogDirectoryIfNecessary();
XnioWorker worker = createWorker(); XnioWorker worker = createWorker();
@ -74,7 +74,6 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
} }
private void createAccessLogDirectoryIfNecessary() { private void createAccessLogDirectoryIfNecessary() {
Assert.state(this.directory != null, "Access log directory is not set");
if (!this.directory.isDirectory() && !this.directory.mkdirs()) { if (!this.directory.isDirectory() && !this.directory.mkdirs()) {
throw new IllegalStateException("Failed to create access log directory '" + this.directory + "'"); throw new IllegalStateException("Failed to create access log directory '" + this.directory + "'");
} }
@ -94,8 +93,8 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
private final XnioWorker worker; private final XnioWorker worker;
ClosableAccessLogHandler(HttpHandler next, XnioWorker worker, DefaultAccessLogReceiver accessLogReceiver, ClosableAccessLogHandler(@Nullable HttpHandler next, XnioWorker worker,
String formatString) { DefaultAccessLogReceiver accessLogReceiver, String formatString) {
super(next, accessLogReceiver, formatString, Undertow.class.getClassLoader()); super(next, accessLogReceiver, formatString, Undertow.class.getClassLoader());
this.worker = worker; this.worker = worker;
this.accessLogReceiver = accessLogReceiver; this.accessLogReceiver = accessLogReceiver;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/CompressionHttpHandlerFactory.java

@ -29,6 +29,7 @@ import io.undertow.server.handlers.encoding.EncodingHandler;
import io.undertow.server.handlers.encoding.GzipEncodingProvider; import io.undertow.server.handlers.encoding.GzipEncodingProvider;
import io.undertow.util.Headers; import io.undertow.util.Headers;
import io.undertow.util.HttpString; import io.undertow.util.HttpString;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.Compression;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@ -51,7 +52,7 @@ class CompressionHttpHandlerFactory implements HttpHandlerFactory {
} }
@Override @Override
public HttpHandler getHandler(HttpHandler next) { public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) {
if (!this.compression.getEnabled()) { if (!this.compression.getEnabled()) {
return next; return next;
} }

17
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/ConfigurableUndertowWebServerFactory.java

@ -20,6 +20,7 @@ import java.io.File;
import java.util.Collection; import java.util.Collection;
import io.undertow.Undertow.Builder; import io.undertow.Undertow.Builder;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.web.server.ConfigurableWebServerFactory; import org.springframework.boot.web.server.ConfigurableWebServerFactory;
@ -50,49 +51,49 @@ public interface ConfigurableUndertowWebServerFactory extends ConfigurableWebSer
* Set the buffer size. * Set the buffer size.
* @param bufferSize buffer size * @param bufferSize buffer size
*/ */
void setBufferSize(Integer bufferSize); void setBufferSize(@Nullable Integer bufferSize);
/** /**
* Set the number of IO Threads. * Set the number of IO Threads.
* @param ioThreads number of IO Threads * @param ioThreads number of IO Threads
*/ */
void setIoThreads(Integer ioThreads); void setIoThreads(@Nullable Integer ioThreads);
/** /**
* Set the number of Worker Threads. * Set the number of Worker Threads.
* @param workerThreads number of Worker Threads * @param workerThreads number of Worker Threads
*/ */
void setWorkerThreads(Integer workerThreads); void setWorkerThreads(@Nullable Integer workerThreads);
/** /**
* Set whether direct buffers should be used. * Set whether direct buffers should be used.
* @param useDirectBuffers whether direct buffers should be used * @param useDirectBuffers whether direct buffers should be used
*/ */
void setUseDirectBuffers(Boolean useDirectBuffers); void setUseDirectBuffers(@Nullable Boolean useDirectBuffers);
/** /**
* Set the access log directory. * Set the access log directory.
* @param accessLogDirectory access log directory * @param accessLogDirectory access log directory
*/ */
void setAccessLogDirectory(File accessLogDirectory); void setAccessLogDirectory(@Nullable File accessLogDirectory);
/** /**
* Set the access log pattern. * Set the access log pattern.
* @param accessLogPattern access log pattern * @param accessLogPattern access log pattern
*/ */
void setAccessLogPattern(String accessLogPattern); void setAccessLogPattern(@Nullable String accessLogPattern);
/** /**
* Set the access log prefix. * Set the access log prefix.
* @param accessLogPrefix log prefix * @param accessLogPrefix log prefix
*/ */
void setAccessLogPrefix(String accessLogPrefix); void setAccessLogPrefix(@Nullable String accessLogPrefix);
/** /**
* Set the access log suffix. * Set the access log suffix.
* @param accessLogSuffix access log suffix * @param accessLogSuffix access log suffix
*/ */
void setAccessLogSuffix(String accessLogSuffix); void setAccessLogSuffix(@Nullable String accessLogSuffix);
/** /**
* Set whether access logs are enabled. * Set whether access logs are enabled.

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/HttpHandlerFactory.java

@ -20,6 +20,7 @@ import java.io.Closeable;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.GracefulShutdownHandler; import io.undertow.server.handlers.GracefulShutdownHandler;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.undertow.servlet.UndertowServletWebServer; import org.springframework.boot.undertow.servlet.UndertowServletWebServer;
@ -43,6 +44,6 @@ public interface HttpHandlerFactory {
* @param next the next handler in the chain * @param next the next handler in the chain
* @return the new HTTP handler instance * @return the new HTTP handler instance
*/ */
HttpHandler getHandler(HttpHandler next); @Nullable HttpHandler getHandler(@Nullable HttpHandler next);
} }

7
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/SslBuilderCustomizer.java

@ -24,6 +24,7 @@ import javax.net.ssl.SSLContext;
import io.undertow.Undertow; import io.undertow.Undertow;
import io.undertow.protocols.ssl.SNIContextMatcher; import io.undertow.protocols.ssl.SNIContextMatcher;
import io.undertow.protocols.ssl.SNISSLContext; import io.undertow.protocols.ssl.SNISSLContext;
import org.jspecify.annotations.Nullable;
import org.xnio.Options; import org.xnio.Options;
import org.xnio.Sequence; import org.xnio.Sequence;
import org.xnio.SslClientAuthMode; import org.xnio.SslClientAuthMode;
@ -44,15 +45,15 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
private final int port; private final int port;
private final InetAddress address; private final @Nullable InetAddress address;
private final ClientAuth clientAuth; private final @Nullable ClientAuth clientAuth;
private final SslBundle sslBundle; private final SslBundle sslBundle;
private final Map<String, SslBundle> serverNameSslBundles; private final Map<String, SslBundle> serverNameSslBundles;
SslBuilderCustomizer(int port, InetAddress address, ClientAuth clientAuth, SslBundle sslBundle, SslBuilderCustomizer(int port, @Nullable InetAddress address, @Nullable ClientAuth clientAuth, SslBundle sslBundle,
Map<String, SslBundle> serverNameSslBundles) { Map<String, SslBundle> serverNameSslBundles) {
this.port = port; this.port = port;
this.address = address; this.address = address;

75
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServer.java

@ -32,6 +32,7 @@ import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.GracefulShutdownHandler; import io.undertow.server.handlers.GracefulShutdownHandler;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.xnio.channels.BoundChannel; import org.xnio.channels.BoundChannel;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
@ -61,7 +62,7 @@ public class UndertowWebServer implements WebServer {
private static final Log logger = LogFactory.getLog(UndertowWebServer.class); private static final Log logger = LogFactory.getLog(UndertowWebServer.class);
private final AtomicReference<GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>(); private final AtomicReference<@Nullable GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>();
private final Object monitor = new Object(); private final Object monitor = new Object();
@ -71,13 +72,13 @@ public class UndertowWebServer implements WebServer {
private final boolean autoStart; private final boolean autoStart;
private Undertow undertow; private @Nullable Undertow undertow;
private volatile boolean started = false; private volatile boolean started = false;
private volatile GracefulShutdownHandler gracefulShutdown; private volatile @Nullable GracefulShutdownHandler gracefulShutdown;
private volatile List<Closeable> closeables; private volatile @Nullable List<Closeable> closeables;
/** /**
* Create a new {@link UndertowWebServer} instance. * Create a new {@link UndertowWebServer} instance.
@ -142,6 +143,7 @@ public class UndertowWebServer implements WebServer {
try { try {
if (this.undertow != null) { if (this.undertow != null) {
this.undertow.stop(); this.undertow.stop();
Assert.state(this.closeables != null, "'closeables' must not be null");
this.closeables.forEach(this::closeSilently); this.closeables.forEach(this::closeSilently);
} }
} }
@ -167,11 +169,12 @@ public class UndertowWebServer implements WebServer {
return this.builder.build(); return this.builder.build();
} }
protected HttpHandler createHttpHandler() { protected @Nullable HttpHandler createHttpHandler() {
HttpHandler handler = null; HttpHandler handler = null;
for (HttpHandlerFactory factory : this.httpHandlerFactories) { for (HttpHandlerFactory factory : this.httpHandlerFactories) {
handler = factory.getHandler(handler); handler = factory.getHandler(handler);
if (handler instanceof Closeable closeable) { if (handler instanceof Closeable closeable) {
Assert.state(this.closeables != null, "'closeables' must not be null");
this.closeables.add(closeable); this.closeables.add(closeable);
} }
if (handler instanceof GracefulShutdownHandler shutdownHandler) { if (handler instanceof GracefulShutdownHandler shutdownHandler) {
@ -220,11 +223,14 @@ public class UndertowWebServer implements WebServer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<BoundChannel> extractChannels() { private List<BoundChannel> extractChannels() {
Field channelsField = ReflectionUtils.findField(Undertow.class, "channels"); Field channelsField = ReflectionUtils.findField(Undertow.class, "channels");
Assert.state(channelsField != null, "'channelsField' must not be null");
ReflectionUtils.makeAccessible(channelsField); ReflectionUtils.makeAccessible(channelsField);
return (List<BoundChannel>) ReflectionUtils.getField(channelsField, this.undertow); List<BoundChannel> channels = (List<BoundChannel>) ReflectionUtils.getField(channelsField, this.undertow);
Assert.state(channels != null, "'channels' must not be null");
return channels;
} }
private UndertowWebServer.Port getPortFromChannel(BoundChannel channel) { private UndertowWebServer.@Nullable Port getPortFromChannel(BoundChannel channel) {
SocketAddress socketAddress = channel.getLocalAddress(); SocketAddress socketAddress = channel.getLocalAddress();
if (socketAddress instanceof InetSocketAddress inetSocketAddress) { if (socketAddress instanceof InetSocketAddress inetSocketAddress) {
Field sslField = ReflectionUtils.findField(channel.getClass(), "ssl"); Field sslField = ReflectionUtils.findField(channel.getClass(), "ssl");
@ -253,20 +259,37 @@ public class UndertowWebServer implements WebServer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<Object> extractListeners() { private List<Object> extractListeners() {
Field listenersField = ReflectionUtils.findField(Undertow.class, "listeners"); Field listenersField = ReflectionUtils.findField(Undertow.class, "listeners");
Assert.state(listenersField != null, "'listenersField' must not be null");
ReflectionUtils.makeAccessible(listenersField); ReflectionUtils.makeAccessible(listenersField);
return (List<Object>) ReflectionUtils.getField(listenersField, this.undertow); List<Object> listeners = (List<Object>) ReflectionUtils.getField(listenersField, this.undertow);
Assert.state(listeners != null, "'listeners' must not be null");
return listeners;
} }
private UndertowWebServer.Port getPortFromListener(Object listener) { private UndertowWebServer.Port getPortFromListener(Object listener) {
Field typeField = ReflectionUtils.findField(listener.getClass(), "type"); Field typeField = ReflectionUtils.findField(listener.getClass(), "type");
ReflectionUtils.makeAccessible(typeField); Assert.state(typeField != null, "'typeField' must not be null");
String protocol = ReflectionUtils.getField(typeField, listener).toString(); String protocol = getProtocol(listener, typeField);
Field portField = ReflectionUtils.findField(listener.getClass(), "port"); Field portField = ReflectionUtils.findField(listener.getClass(), "port");
ReflectionUtils.makeAccessible(portField); Assert.state(portField != null, "'portField' must not be null");
int port = (Integer) ReflectionUtils.getField(portField, listener); int port = getPort(listener, portField);
return new UndertowWebServer.Port(port, protocol); return new UndertowWebServer.Port(port, protocol);
} }
private static Integer getPort(Object listener, Field portField) {
ReflectionUtils.makeAccessible(portField);
Integer value = (Integer) ReflectionUtils.getField(portField, listener);
Assert.state(value != null, "'value' must not be null");
return value;
}
private String getProtocol(Object listener, Field typeField) {
ReflectionUtils.makeAccessible(typeField);
Object value = ReflectionUtils.getField(typeField, listener);
Assert.state(value != null, "'value' must not be null");
return value.toString();
}
@Override @Override
public void stop() throws WebServerException { public void stop() throws WebServerException {
synchronized (this.monitor) { synchronized (this.monitor) {
@ -278,9 +301,12 @@ public class UndertowWebServer implements WebServer {
notifyGracefulCallback(false); notifyGracefulCallback(false);
} }
try { try {
this.undertow.stop(); if (this.undertow != null) {
for (Closeable closeable : this.closeables) { this.undertow.stop();
closeable.close(); Assert.state(this.closeables != null, "'closeables' must not be null");
for (Closeable closeable : this.closeables) {
closeable.close();
}
} }
} }
catch (Exception ex) { catch (Exception ex) {
@ -304,7 +330,7 @@ public class UndertowWebServer implements WebServer {
* @return the Undertow server or {@code null} if the server hasn't been started yet * @return the Undertow server or {@code null} if the server hasn't been started yet
* @since 4.0.0 * @since 4.0.0
*/ */
public Undertow getUndertow() { public @Nullable Undertow getUndertow() {
return this.undertow; return this.undertow;
} }
@ -396,27 +422,30 @@ public class UndertowWebServer implements WebServer {
*/ */
private static final class CloseableHttpHandlerFactory implements HttpHandlerFactory { private static final class CloseableHttpHandlerFactory implements HttpHandlerFactory {
private final Closeable closeable; private final @Nullable Closeable closeable;
private CloseableHttpHandlerFactory(Closeable closeable) { private CloseableHttpHandlerFactory(@Nullable Closeable closeable) {
this.closeable = closeable; this.closeable = closeable;
} }
@Override @Override
public HttpHandler getHandler(HttpHandler next) { public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) {
if (this.closeable == null) { Closeable closeable = this.closeable;
if (closeable == null) {
return next; return next;
} }
return new CloseableHttpHandler() { return new CloseableHttpHandler() {
@Override @Override
public void handleRequest(HttpServerExchange exchange) throws Exception { public void handleRequest(HttpServerExchange exchange) throws Exception {
next.handleRequest(exchange); if (next != null) {
next.handleRequest(exchange);
}
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
CloseableHttpHandlerFactory.this.closeable.close(); closeable.close();
} }
}; };
@ -438,7 +467,7 @@ public class UndertowWebServer implements WebServer {
static class UndertowWebServerRuntimeHints implements RuntimeHintsRegistrar { static class UndertowWebServerRuntimeHints implements RuntimeHintsRegistrar {
@Override @Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) { public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection() hints.reflection()
.registerTypeIfPresent(classLoader, "io.undertow.Undertow", .registerTypeIfPresent(classLoader, "io.undertow.Undertow",
(hint) -> hint.withField("listeners").withField("channels")); (hint) -> hint.withField("listeners").withField("channels"));

41
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/UndertowWebServerFactory.java

@ -31,6 +31,7 @@ import io.undertow.Handlers;
import io.undertow.Undertow; import io.undertow.Undertow;
import io.undertow.Undertow.Builder; import io.undertow.Undertow.Builder;
import io.undertow.UndertowOptions; import io.undertow.UndertowOptions;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory; import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
@ -52,21 +53,21 @@ public abstract class UndertowWebServerFactory extends AbstractConfigurableWebSe
private Set<UndertowBuilderCustomizer> builderCustomizers = new LinkedHashSet<>(); private Set<UndertowBuilderCustomizer> builderCustomizers = new LinkedHashSet<>();
private Integer bufferSize; private @Nullable Integer bufferSize;
private Integer ioThreads; private @Nullable Integer ioThreads;
private Integer workerThreads; private @Nullable Integer workerThreads;
private Boolean directBuffers; private @Nullable Boolean directBuffers;
private File accessLogDirectory; private @Nullable File accessLogDirectory;
private String accessLogPattern; private @Nullable String accessLogPattern;
private String accessLogPrefix; private @Nullable String accessLogPrefix;
private String accessLogSuffix; private @Nullable String accessLogSuffix;
private boolean accessLogEnabled; private boolean accessLogEnabled;
@ -98,46 +99,46 @@ public abstract class UndertowWebServerFactory extends AbstractConfigurableWebSe
} }
@Override @Override
public void setBufferSize(Integer bufferSize) { public void setBufferSize(@Nullable Integer bufferSize) {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
} }
@Override @Override
public void setIoThreads(Integer ioThreads) { public void setIoThreads(@Nullable Integer ioThreads) {
this.ioThreads = ioThreads; this.ioThreads = ioThreads;
} }
@Override @Override
public void setWorkerThreads(Integer workerThreads) { public void setWorkerThreads(@Nullable Integer workerThreads) {
this.workerThreads = workerThreads; this.workerThreads = workerThreads;
} }
@Override @Override
public void setUseDirectBuffers(Boolean directBuffers) { public void setUseDirectBuffers(@Nullable Boolean directBuffers) {
this.directBuffers = directBuffers; this.directBuffers = directBuffers;
} }
@Override @Override
public void setAccessLogDirectory(File accessLogDirectory) { public void setAccessLogDirectory(@Nullable File accessLogDirectory) {
this.accessLogDirectory = accessLogDirectory; this.accessLogDirectory = accessLogDirectory;
} }
@Override @Override
public void setAccessLogPattern(String accessLogPattern) { public void setAccessLogPattern(@Nullable String accessLogPattern) {
this.accessLogPattern = accessLogPattern; this.accessLogPattern = accessLogPattern;
} }
@Override @Override
public void setAccessLogPrefix(String accessLogPrefix) { public void setAccessLogPrefix(@Nullable String accessLogPrefix) {
this.accessLogPrefix = accessLogPrefix; this.accessLogPrefix = accessLogPrefix;
} }
public String getAccessLogPrefix() { public @Nullable String getAccessLogPrefix() {
return this.accessLogPrefix; return this.accessLogPrefix;
} }
@Override @Override
public void setAccessLogSuffix(String accessLogSuffix) { public void setAccessLogSuffix(@Nullable String accessLogSuffix) {
this.accessLogSuffix = accessLogSuffix; this.accessLogSuffix = accessLogSuffix;
} }
@ -207,14 +208,16 @@ public abstract class UndertowWebServerFactory extends AbstractConfigurableWebSe
this.useForwardHeaders, webServerFactory.getServerHeader(), webServerFactory.getShutdown(), this.useForwardHeaders, webServerFactory.getServerHeader(), webServerFactory.getShutdown(),
initialHttpHandlerFactories); initialHttpHandlerFactories);
if (isAccessLogEnabled()) { if (isAccessLogEnabled()) {
Assert.state(this.accessLogDirectory != null, "Access log directory is not set");
factories.add(new AccessLogHttpHandlerFactory(this.accessLogDirectory, this.accessLogPattern, factories.add(new AccessLogHttpHandlerFactory(this.accessLogDirectory, this.accessLogPattern,
this.accessLogPrefix, this.accessLogSuffix, this.accessLogRotate)); this.accessLogPrefix, this.accessLogSuffix, this.accessLogRotate));
} }
return factories; return factories;
} }
static List<HttpHandlerFactory> createHttpHandlerFactories(Compression compression, boolean useForwardHeaders, static List<HttpHandlerFactory> createHttpHandlerFactories(@Nullable Compression compression,
String serverHeader, Shutdown shutdown, HttpHandlerFactory... initialHttpHandlerFactories) { boolean useForwardHeaders, @Nullable String serverHeader, Shutdown shutdown,
HttpHandlerFactory... initialHttpHandlerFactories) {
List<HttpHandlerFactory> factories = new ArrayList<>(Arrays.asList(initialHttpHandlerFactories)); List<HttpHandlerFactory> factories = new ArrayList<>(Arrays.asList(initialHttpHandlerFactories));
if (compression != null && compression.getEnabled()) { if (compression != null && compression.getEnabled()) {
factories.add(new CompressionHttpHandlerFactory(compression)); factories.add(new CompressionHttpHandlerFactory(compression));

37
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/UndertowServerProperties.java

@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import io.undertow.UndertowOptions; import io.undertow.UndertowOptions;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.unit.DataSize; import org.springframework.util.unit.DataSize;
@ -69,13 +70,13 @@ public class UndertowServerProperties {
* Size of each buffer. The default is derived from the maximum amount of memory that * Size of each buffer. The default is derived from the maximum amount of memory that
* is available to the JVM. * is available to the JVM.
*/ */
private DataSize bufferSize; private @Nullable DataSize bufferSize;
/** /**
* Whether to allocate buffers outside the Java heap. The default is derived from the * Whether to allocate buffers outside the Java heap. The default is derived from the
* maximum amount of memory that is available to the JVM. * maximum amount of memory that is available to the JVM.
*/ */
private Boolean directBuffers; private @Nullable Boolean directBuffers;
/** /**
* Whether servlet filters should be initialized on startup. * Whether servlet filters should be initialized on startup.
@ -106,7 +107,7 @@ public class UndertowServerProperties {
* enable this if you have a legacy application that requires it. When set, * enable this if you have a legacy application that requires it. When set,
* server.undertow.allow-encoded-slash has no effect. * server.undertow.allow-encoded-slash has no effect.
*/ */
private Boolean decodeSlash; private @Nullable Boolean decodeSlash;
/** /**
* Whether the URL should be decoded. When disabled, percent-encoded characters in the * Whether the URL should be decoded. When disabled, percent-encoded characters in the
@ -129,7 +130,7 @@ public class UndertowServerProperties {
* Amount of time a connection can sit idle without processing a request, before it is * Amount of time a connection can sit idle without processing a request, before it is
* closed by the server. * closed by the server.
*/ */
private Duration noRequestTimeout; private @Nullable Duration noRequestTimeout;
/** /**
* Whether to preserve the path of a request when it is forwarded. * Whether to preserve the path of a request when it is forwarded.
@ -153,19 +154,19 @@ public class UndertowServerProperties {
this.maxHttpPostSize = maxHttpPostSize; this.maxHttpPostSize = maxHttpPostSize;
} }
public DataSize getBufferSize() { public @Nullable DataSize getBufferSize() {
return this.bufferSize; return this.bufferSize;
} }
public void setBufferSize(DataSize bufferSize) { public void setBufferSize(@Nullable DataSize bufferSize) {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
} }
public Boolean getDirectBuffers() { public @Nullable Boolean getDirectBuffers() {
return this.directBuffers; return this.directBuffers;
} }
public void setDirectBuffers(Boolean directBuffers) { public void setDirectBuffers(@Nullable Boolean directBuffers) {
this.directBuffers = directBuffers; this.directBuffers = directBuffers;
} }
@ -201,11 +202,11 @@ public class UndertowServerProperties {
this.maxCookies = maxCookies; this.maxCookies = maxCookies;
} }
public Boolean getDecodeSlash() { public @Nullable Boolean getDecodeSlash() {
return this.decodeSlash; return this.decodeSlash;
} }
public void setDecodeSlash(Boolean decodeSlash) { public void setDecodeSlash(@Nullable Boolean decodeSlash) {
this.decodeSlash = decodeSlash; this.decodeSlash = decodeSlash;
} }
@ -233,11 +234,11 @@ public class UndertowServerProperties {
this.alwaysSetKeepAlive = alwaysSetKeepAlive; this.alwaysSetKeepAlive = alwaysSetKeepAlive;
} }
public Duration getNoRequestTimeout() { public @Nullable Duration getNoRequestTimeout() {
return this.noRequestTimeout; return this.noRequestTimeout;
} }
public void setNoRequestTimeout(Duration noRequestTimeout) { public void setNoRequestTimeout(@Nullable Duration noRequestTimeout) {
this.noRequestTimeout = noRequestTimeout; this.noRequestTimeout = noRequestTimeout;
} }
@ -355,26 +356,26 @@ public class UndertowServerProperties {
* Number of I/O threads to create for the worker. The default is derived from the * Number of I/O threads to create for the worker. The default is derived from the
* number of available processors. * number of available processors.
*/ */
private Integer io; private @Nullable Integer io;
/** /**
* Number of worker threads. The default is 8 times the number of I/O threads. * Number of worker threads. The default is 8 times the number of I/O threads.
*/ */
private Integer worker; private @Nullable Integer worker;
public Integer getIo() { public @Nullable Integer getIo() {
return this.io; return this.io;
} }
public void setIo(Integer io) { public void setIo(@Nullable Integer io) {
this.io = io; this.io = io;
} }
public Integer getWorker() { public @Nullable Integer getWorker() {
return this.worker; return this.worker;
} }
public void setWorker(Integer worker) { public void setWorker(@Nullable Integer worker) {
this.worker = worker; this.worker = worker;
} }

6
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/UndertowAccessLogCustomizer.java

@ -18,6 +18,8 @@ package org.springframework.boot.undertow.autoconfigure.actuate.web.server;
import java.util.function.Function; import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer; import org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer;
import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory; import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory;
@ -29,10 +31,10 @@ import org.springframework.boot.undertow.ConfigurableUndertowWebServerFactory;
*/ */
class UndertowAccessLogCustomizer<T extends ConfigurableUndertowWebServerFactory> extends AccessLogCustomizer<T> { class UndertowAccessLogCustomizer<T extends ConfigurableUndertowWebServerFactory> extends AccessLogCustomizer<T> {
private final Function<T, String> accessLogPrefixExtractor; private final Function<T, @Nullable String> accessLogPrefixExtractor;
UndertowAccessLogCustomizer(UndertowManagementServerProperties properties, UndertowAccessLogCustomizer(UndertowManagementServerProperties properties,
Function<T, String> accessLogPrefixExtractor) { Function<T, @Nullable String> accessLogPrefixExtractor) {
super(properties.getAccesslog().getPrefix()); super(properties.getAccesslog().getPrefix());
this.accessLogPrefixExtractor = accessLogPrefixExtractor; this.accessLogPrefixExtractor = accessLogPrefixExtractor;
} }

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/actuate/web/server/package-info.java

@ -17,4 +17,7 @@
/** /**
* Actuator Undertow actuator web concerns. * Actuator Undertow actuator web concerns.
*/ */
@NullMarked
package org.springframework.boot.undertow.autoconfigure.actuate.web.server; package org.springframework.boot.undertow.autoconfigure.actuate.web.server;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/package-info.java

@ -18,4 +18,7 @@
* Classes related to the auto-configuration of a servlet or reactive web server using * Classes related to the auto-configuration of a servlet or reactive web server using
* Undertow. * Undertow.
*/ */
@NullMarked
package org.springframework.boot.undertow.autoconfigure; package org.springframework.boot.undertow.autoconfigure;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/reactive/package-info.java

@ -17,4 +17,7 @@
/** /**
* Classes related to the auto-configuration of a reactive web server using Undertow. * Classes related to the auto-configuration of a reactive web server using Undertow.
*/ */
@NullMarked
package org.springframework.boot.undertow.autoconfigure.reactive; package org.springframework.boot.undertow.autoconfigure.reactive;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/autoconfigure/servlet/package-info.java

@ -17,4 +17,7 @@
/** /**
* Classes related to the auto-configuration of a servlet web server using Undertow. * Classes related to the auto-configuration of a servlet web server using Undertow.
*/ */
@NullMarked
package org.springframework.boot.undertow.autoconfigure.servlet; package org.springframework.boot.undertow.autoconfigure.servlet;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/package-info.java

@ -20,4 +20,7 @@
* @see org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory * @see org.springframework.boot.undertow.servlet.UndertowServletWebServerFactory
* @see org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory * @see org.springframework.boot.undertow.reactive.UndertowReactiveWebServerFactory
*/ */
@NullMarked
package org.springframework.boot.undertow; package org.springframework.boot.undertow;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/reactive/package-info.java

@ -17,4 +17,7 @@
/** /**
* Reactive web server implementation backed by Undertow. * Reactive web server implementation backed by Undertow.
*/ */
@NullMarked
package org.springframework.boot.undertow.reactive; package org.springframework.boot.undertow.reactive;
import org.jspecify.annotations.NullMarked;

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/CompositeResourceManager.java

@ -24,6 +24,7 @@ import io.undertow.UndertowMessages;
import io.undertow.server.handlers.resource.Resource; import io.undertow.server.handlers.resource.Resource;
import io.undertow.server.handlers.resource.ResourceChangeListener; import io.undertow.server.handlers.resource.ResourceChangeListener;
import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.ResourceManager;
import org.jspecify.annotations.Nullable;
/** /**
* A {@link ResourceManager} that delegates to multiple {@code ResourceManager} instances. * A {@link ResourceManager} that delegates to multiple {@code ResourceManager} instances.
@ -46,7 +47,7 @@ class CompositeResourceManager implements ResourceManager {
} }
@Override @Override
public Resource getResource(String path) throws IOException { public @Nullable Resource getResource(String path) throws IOException {
for (ResourceManager resourceManager : this.resourceManagers) { for (ResourceManager resourceManager : this.resourceManagers) {
Resource resource = resourceManager.getResource(path); Resource resource = resourceManager.getResource(path);
if (resource != null) { if (resource != null) {

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/DeploymentManagerHttpHandlerFactory.java

@ -23,6 +23,7 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.undertow.HttpHandlerFactory; import org.springframework.boot.undertow.HttpHandlerFactory;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -42,7 +43,7 @@ class DeploymentManagerHttpHandlerFactory implements HttpHandlerFactory {
} }
@Override @Override
public HttpHandler getHandler(HttpHandler next) { public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) {
Assert.state(next == null, "DeploymentManagerHttpHandlerFactory must be first"); Assert.state(next == null, "DeploymentManagerHttpHandlerFactory must be first");
return new DeploymentManagerHandler(this.deploymentManager); return new DeploymentManagerHandler(this.deploymentManager);
} }

4
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/FileSessionPersistence.java

@ -29,6 +29,7 @@ import java.util.Map;
import io.undertow.servlet.UndertowServletLogger; import io.undertow.servlet.UndertowServletLogger;
import io.undertow.servlet.api.SessionPersistenceManager; import io.undertow.servlet.api.SessionPersistenceManager;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ConfigurableObjectInputStream; import org.springframework.core.ConfigurableObjectInputStream;
@ -70,7 +71,8 @@ class FileSessionPersistence implements SessionPersistenceManager {
} }
@Override @Override
public Map<String, PersistentSession> loadSessionAttributes(String deploymentName, final ClassLoader classLoader) { public @Nullable Map<String, PersistentSession> loadSessionAttributes(String deploymentName,
final ClassLoader classLoader) {
try { try {
File file = getSessionFile(deploymentName); File file = getSessionFile(deploymentName);
if (file.exists()) { if (file.exists()) {

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/JarResourceManager.java

@ -26,6 +26,7 @@ import io.undertow.server.handlers.resource.Resource;
import io.undertow.server.handlers.resource.ResourceChangeListener; import io.undertow.server.handlers.resource.ResourceChangeListener;
import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.ResourceManager;
import io.undertow.server.handlers.resource.URLResource; import io.undertow.server.handlers.resource.URLResource;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -49,7 +50,7 @@ class JarResourceManager implements ResourceManager {
} }
@Override @Override
public Resource getResource(String path) throws IOException { public @Nullable Resource getResource(String path) throws IOException {
URL url = new URL("jar:" + this.jarPath + "!" + (path.startsWith("/") ? path : "/" + path)); URL url = new URL("jar:" + this.jarPath + "!" + (path.startsWith("/") ? path : "/" + path));
URLResource resource = new URLResource(url, path); URLResource resource = new URLResource(url, path);
if (StringUtils.hasText(path) && !"/".equals(path) && resource.getContentLength() < 0) { if (StringUtils.hasText(path) && !"/".equals(path) && resource.getContentLength() < 0) {

9
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServer.java

@ -20,6 +20,7 @@ import io.undertow.Handlers;
import io.undertow.Undertow.Builder; import io.undertow.Undertow.Builder;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.undertow.HttpHandlerFactory; import org.springframework.boot.undertow.HttpHandlerFactory;
import org.springframework.boot.undertow.UndertowWebServer; import org.springframework.boot.undertow.UndertowWebServer;
@ -43,7 +44,7 @@ public class UndertowServletWebServer extends UndertowWebServer {
private final String contextPath; private final String contextPath;
private final DeploymentManager manager; private final @Nullable DeploymentManager manager;
/** /**
* Create a new {@link UndertowServletWebServer} instance. * Create a new {@link UndertowServletWebServer} instance.
@ -60,7 +61,7 @@ public class UndertowServletWebServer extends UndertowWebServer {
this.manager = findManager(httpHandlerFactories); this.manager = findManager(httpHandlerFactories);
} }
private DeploymentManager findManager(Iterable<HttpHandlerFactory> httpHandlerFactories) { private @Nullable DeploymentManager findManager(Iterable<HttpHandlerFactory> httpHandlerFactories) {
for (HttpHandlerFactory httpHandlerFactory : httpHandlerFactories) { for (HttpHandlerFactory httpHandlerFactory : httpHandlerFactories) {
if (httpHandlerFactory instanceof DeploymentManagerHttpHandlerFactory deploymentManagerFactory) { if (httpHandlerFactory instanceof DeploymentManagerHttpHandlerFactory deploymentManagerFactory) {
return deploymentManagerFactory.getDeploymentManager(); return deploymentManagerFactory.getDeploymentManager();
@ -70,7 +71,7 @@ public class UndertowServletWebServer extends UndertowWebServer {
} }
@Override @Override
protected HttpHandler createHttpHandler() { protected @Nullable HttpHandler createHttpHandler() {
HttpHandler handler = super.createHttpHandler(); HttpHandler handler = super.createHttpHandler();
if (StringUtils.hasLength(this.contextPath)) { if (StringUtils.hasLength(this.contextPath)) {
handler = Handlers.path().addPrefixPath(this.contextPath, handler); handler = Handlers.path().addPrefixPath(this.contextPath, handler);
@ -88,7 +89,7 @@ public class UndertowServletWebServer extends UndertowWebServer {
return message.toString(); return message.toString();
} }
public DeploymentManager getDeploymentManager() { public @Nullable DeploymentManager getDeploymentManager() {
return this.manager; return this.manager;
} }

30
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/UndertowServletWebServerFactory.java

@ -61,6 +61,7 @@ import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.undertow.HttpHandlerFactory; import org.springframework.boot.undertow.HttpHandlerFactory;
@ -110,6 +111,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
private Set<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers = new LinkedHashSet<>(); private Set<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers = new LinkedHashSet<>();
@SuppressWarnings("NullAway.Init")
private ResourceLoader resourceLoader; private ResourceLoader resourceLoader;
private boolean eagerFilterInit = true; private boolean eagerFilterInit = true;
@ -273,10 +275,12 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Class<? extends EventListener> loadWebListenerClass(String className) throws ClassNotFoundException { private Class<? extends EventListener> loadWebListenerClass(String className) throws ClassNotFoundException {
return (Class<? extends EventListener>) getServletClassLoader().loadClass(className); ClassLoader classLoader = getServletClassLoader();
Assert.state(classLoader != null, "'classLoader' must not be null");
return (Class<? extends EventListener>) classLoader.loadClass(className);
} }
private boolean isZeroOrLess(Duration timeoutDuration) { private boolean isZeroOrLess(@Nullable Duration timeoutDuration) {
return timeoutDuration == null || timeoutDuration.isZero() || timeoutDuration.isNegative(); return timeoutDuration == null || timeoutDuration.isZero() || timeoutDuration.isNegative();
} }
@ -293,7 +297,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
new ImmediateInstanceFactory<>(initializer), NO_CLASSES)); new ImmediateInstanceFactory<>(initializer), NO_CLASSES));
} }
private ClassLoader getServletClassLoader() { private @Nullable ClassLoader getServletClassLoader() {
if (this.resourceLoader != null) { if (this.resourceLoader != null) {
return this.resourceLoader.getClassLoader(); return this.resourceLoader.getClassLoader();
} }
@ -337,7 +341,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
return new CompositeResourceManager(managers.toArray(new ResourceManager[0])); return new CompositeResourceManager(managers.toArray(new ResourceManager[0]));
} }
private File getCanonicalDocumentRoot(File docBase) { private File getCanonicalDocumentRoot(@Nullable File docBase) {
try { try {
File root = (docBase != null) ? docBase : createTempDir("undertow-docbase"); File root = (docBase != null) ? docBase : createTempDir("undertow-docbase");
return root.getCanonicalFile(); return root.getCanonicalFile();
@ -402,7 +406,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
port >= 0); port >= 0);
} }
private HttpHandlerFactory getCookieHandlerFactory(Deployment deployment) { private @Nullable HttpHandlerFactory getCookieHandlerFactory(Deployment deployment) {
SameSite sessionSameSite = getSettings().getSession().getCookie().getSameSite(); SameSite sessionSameSite = getSettings().getSession().getCookie().getSameSite();
List<CookieSameSiteSupplier> suppliers = new ArrayList<>(); List<CookieSameSiteSupplier> suppliers = new ArrayList<>();
if (sessionSameSite != null) { if (sessionSameSite != null) {
@ -458,7 +462,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
} }
@Override @Override
public Resource getResource(String path) { public @Nullable Resource getResource(String path) {
for (URL url : this.metaInfResourceJarUrls) { for (URL url : this.metaInfResourceJarUrls) {
URLResource resource = getMetaInfResource(url, path); URLResource resource = getMetaInfResource(url, path);
if (resource != null) { if (resource != null) {
@ -482,7 +486,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
} }
private URLResource getMetaInfResource(URL resourceJar, String path) { private @Nullable URLResource getMetaInfResource(URL resourceJar, String path) {
try { try {
String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), StandardCharsets.UTF_8); String urlPath = URLEncoder.encode(ENCODED_SLASH.matcher(path).replaceAll("/"), StandardCharsets.UTF_8);
URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath); URL resourceUrl = new URL(resourceJar + "META-INF/resources" + urlPath);
@ -511,7 +515,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
} }
@Override @Override
public Resource getResource(String path) throws IOException { public @Nullable Resource getResource(String path) throws IOException {
if (path.startsWith("/org/springframework/boot")) { if (path.startsWith("/org/springframework/boot")) {
return null; return null;
} }
@ -546,11 +550,11 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
*/ */
private static class SuppliedSameSiteCookieHandler implements HttpHandler { private static class SuppliedSameSiteCookieHandler implements HttpHandler {
private final HttpHandler next; private final @Nullable HttpHandler next;
private final List<CookieSameSiteSupplier> suppliers; private final List<CookieSameSiteSupplier> suppliers;
SuppliedSameSiteCookieHandler(HttpHandler next, List<CookieSameSiteSupplier> suppliers) { SuppliedSameSiteCookieHandler(@Nullable HttpHandler next, List<CookieSameSiteSupplier> suppliers) {
this.next = next; this.next = next;
this.suppliers = suppliers; this.suppliers = suppliers;
} }
@ -558,7 +562,9 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
@Override @Override
public void handleRequest(HttpServerExchange exchange) throws Exception { public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.addResponseCommitListener(this::beforeCommit); exchange.addResponseCommitListener(this::beforeCommit);
this.next.handleRequest(exchange); if (this.next != null) {
this.next.handleRequest(exchange);
}
} }
private void beforeCommit(HttpServerExchange exchange) { private void beforeCommit(HttpServerExchange exchange) {
@ -587,7 +593,7 @@ public class UndertowServletWebServerFactory extends UndertowWebServerFactory
return result; return result;
} }
private SameSite getSameSite(jakarta.servlet.http.Cookie cookie) { private @Nullable SameSite getSameSite(jakarta.servlet.http.Cookie cookie) {
for (CookieSameSiteSupplier supplier : this.suppliers) { for (CookieSameSiteSupplier supplier : this.suppliers) {
SameSite sameSite = supplier.getSameSite(cookie); SameSite sameSite = supplier.getSameSite(cookie);
if (sameSite != null) { if (sameSite != null) {

3
module/spring-boot-undertow/src/main/java/org/springframework/boot/undertow/servlet/package-info.java

@ -17,4 +17,7 @@
/** /**
* Servlet web server implementation backed by Undertow. * Servlet web server implementation backed by Undertow.
*/ */
@NullMarked
package org.springframework.boot.undertow.servlet; package org.springframework.boot.undertow.servlet;
import org.jspecify.annotations.NullMarked;

Loading…
Cancel
Save