Skip to content

Commit e327eb7

Browse files
committed
Add nullability annotations to module/spring-boot-undertow
See gh-46587
1 parent 89a5bfd commit e327eb7

22 files changed

+176
-105
lines changed

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,12 @@
2525
import io.undertow.server.HttpHandler;
2626
import io.undertow.server.handlers.accesslog.AccessLogHandler;
2727
import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver;
28+
import org.jspecify.annotations.Nullable;
2829
import org.xnio.OptionMap;
2930
import org.xnio.Options;
3031
import org.xnio.Xnio;
3132
import org.xnio.XnioWorker;
3233

33-
import org.springframework.util.Assert;
34-
3534
/**
3635
* An {@link HttpHandlerFactory} for an {@link AccessLogHandler}.
3736
*
@@ -41,15 +40,16 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
4140

4241
private final File directory;
4342

44-
private final String pattern;
43+
private final @Nullable String pattern;
4544

46-
private final String prefix;
45+
private final @Nullable String prefix;
4746

48-
private final String suffix;
47+
private final @Nullable String suffix;
4948

5049
private final boolean rotate;
5150

52-
AccessLogHttpHandlerFactory(File directory, String pattern, String prefix, String suffix, boolean rotate) {
51+
AccessLogHttpHandlerFactory(File directory, @Nullable String pattern, @Nullable String prefix,
52+
@Nullable String suffix, boolean rotate) {
5353
this.directory = directory;
5454
this.pattern = pattern;
5555
this.prefix = prefix;
@@ -58,7 +58,7 @@ class AccessLogHttpHandlerFactory implements HttpHandlerFactory {
5858
}
5959

6060
@Override
61-
public HttpHandler getHandler(HttpHandler next) {
61+
public HttpHandler getHandler(@Nullable HttpHandler next) {
6262
try {
6363
createAccessLogDirectoryIfNecessary();
6464
XnioWorker worker = createWorker();
@@ -74,7 +74,6 @@ public HttpHandler getHandler(HttpHandler next) {
7474
}
7575

7676
private void createAccessLogDirectoryIfNecessary() {
77-
Assert.state(this.directory != null, "Access log directory is not set");
7877
if (!this.directory.isDirectory() && !this.directory.mkdirs()) {
7978
throw new IllegalStateException("Failed to create access log directory '" + this.directory + "'");
8079
}
@@ -94,8 +93,8 @@ private static class ClosableAccessLogHandler extends AccessLogHandler implement
9493

9594
private final XnioWorker worker;
9695

97-
ClosableAccessLogHandler(HttpHandler next, XnioWorker worker, DefaultAccessLogReceiver accessLogReceiver,
98-
String formatString) {
96+
ClosableAccessLogHandler(@Nullable HttpHandler next, XnioWorker worker,
97+
DefaultAccessLogReceiver accessLogReceiver, String formatString) {
9998
super(next, accessLogReceiver, formatString, Undertow.class.getClassLoader());
10099
this.worker = worker;
101100
this.accessLogReceiver = accessLogReceiver;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.undertow.server.handlers.encoding.GzipEncodingProvider;
3030
import io.undertow.util.Headers;
3131
import io.undertow.util.HttpString;
32+
import org.jspecify.annotations.Nullable;
3233

3334
import org.springframework.boot.web.server.Compression;
3435
import org.springframework.http.HttpHeaders;
@@ -51,7 +52,7 @@ class CompressionHttpHandlerFactory implements HttpHandlerFactory {
5152
}
5253

5354
@Override
54-
public HttpHandler getHandler(HttpHandler next) {
55+
public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) {
5556
if (!this.compression.getEnabled()) {
5657
return next;
5758
}

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Collection;
2121

2222
import io.undertow.Undertow.Builder;
23+
import org.jspecify.annotations.Nullable;
2324

2425
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
2526

@@ -50,49 +51,49 @@ public interface ConfigurableUndertowWebServerFactory extends ConfigurableWebSer
5051
* Set the buffer size.
5152
* @param bufferSize buffer size
5253
*/
53-
void setBufferSize(Integer bufferSize);
54+
void setBufferSize(@Nullable Integer bufferSize);
5455

5556
/**
5657
* Set the number of IO Threads.
5758
* @param ioThreads number of IO Threads
5859
*/
59-
void setIoThreads(Integer ioThreads);
60+
void setIoThreads(@Nullable Integer ioThreads);
6061

6162
/**
6263
* Set the number of Worker Threads.
6364
* @param workerThreads number of Worker Threads
6465
*/
65-
void setWorkerThreads(Integer workerThreads);
66+
void setWorkerThreads(@Nullable Integer workerThreads);
6667

6768
/**
6869
* Set whether direct buffers should be used.
6970
* @param useDirectBuffers whether direct buffers should be used
7071
*/
71-
void setUseDirectBuffers(Boolean useDirectBuffers);
72+
void setUseDirectBuffers(@Nullable Boolean useDirectBuffers);
7273

7374
/**
7475
* Set the access log directory.
7576
* @param accessLogDirectory access log directory
7677
*/
77-
void setAccessLogDirectory(File accessLogDirectory);
78+
void setAccessLogDirectory(@Nullable File accessLogDirectory);
7879

7980
/**
8081
* Set the access log pattern.
8182
* @param accessLogPattern access log pattern
8283
*/
83-
void setAccessLogPattern(String accessLogPattern);
84+
void setAccessLogPattern(@Nullable String accessLogPattern);
8485

8586
/**
8687
* Set the access log prefix.
8788
* @param accessLogPrefix log prefix
8889
*/
89-
void setAccessLogPrefix(String accessLogPrefix);
90+
void setAccessLogPrefix(@Nullable String accessLogPrefix);
9091

9192
/**
9293
* Set the access log suffix.
9394
* @param accessLogSuffix access log suffix
9495
*/
95-
void setAccessLogSuffix(String accessLogSuffix);
96+
void setAccessLogSuffix(@Nullable String accessLogSuffix);
9697

9798
/**
9899
* Set whether access logs are enabled.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import io.undertow.server.HttpHandler;
2222
import io.undertow.server.handlers.GracefulShutdownHandler;
23+
import org.jspecify.annotations.Nullable;
2324

2425
import org.springframework.boot.undertow.servlet.UndertowServletWebServer;
2526

@@ -43,6 +44,6 @@ public interface HttpHandlerFactory {
4344
* @param next the next handler in the chain
4445
* @return the new HTTP handler instance
4546
*/
46-
HttpHandler getHandler(HttpHandler next);
47+
@Nullable HttpHandler getHandler(@Nullable HttpHandler next);
4748

4849
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.undertow.Undertow;
2525
import io.undertow.protocols.ssl.SNIContextMatcher;
2626
import io.undertow.protocols.ssl.SNISSLContext;
27+
import org.jspecify.annotations.Nullable;
2728
import org.xnio.Options;
2829
import org.xnio.Sequence;
2930
import org.xnio.SslClientAuthMode;
@@ -44,15 +45,15 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
4445

4546
private final int port;
4647

47-
private final InetAddress address;
48+
private final @Nullable InetAddress address;
4849

49-
private final ClientAuth clientAuth;
50+
private final @Nullable ClientAuth clientAuth;
5051

5152
private final SslBundle sslBundle;
5253

5354
private final Map<String, SslBundle> serverNameSslBundles;
5455

55-
SslBuilderCustomizer(int port, InetAddress address, ClientAuth clientAuth, SslBundle sslBundle,
56+
SslBuilderCustomizer(int port, @Nullable InetAddress address, @Nullable ClientAuth clientAuth, SslBundle sslBundle,
5657
Map<String, SslBundle> serverNameSslBundles) {
5758
this.port = port;
5859
this.address = address;

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

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import io.undertow.server.handlers.GracefulShutdownHandler;
3333
import org.apache.commons.logging.Log;
3434
import org.apache.commons.logging.LogFactory;
35+
import org.jspecify.annotations.Nullable;
3536
import org.xnio.channels.BoundChannel;
3637

3738
import org.springframework.aot.hint.RuntimeHints;
@@ -61,7 +62,7 @@ public class UndertowWebServer implements WebServer {
6162

6263
private static final Log logger = LogFactory.getLog(UndertowWebServer.class);
6364

64-
private final AtomicReference<GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>();
65+
private final AtomicReference<@Nullable GracefulShutdownCallback> gracefulShutdownCallback = new AtomicReference<>();
6566

6667
private final Object monitor = new Object();
6768

@@ -71,13 +72,13 @@ public class UndertowWebServer implements WebServer {
7172

7273
private final boolean autoStart;
7374

74-
private Undertow undertow;
75+
private @Nullable Undertow undertow;
7576

7677
private volatile boolean started = false;
7778

78-
private volatile GracefulShutdownHandler gracefulShutdown;
79+
private volatile @Nullable GracefulShutdownHandler gracefulShutdown;
7980

80-
private volatile List<Closeable> closeables;
81+
private volatile @Nullable List<Closeable> closeables;
8182

8283
/**
8384
* Create a new {@link UndertowWebServer} instance.
@@ -142,6 +143,7 @@ private void destroySilently() {
142143
try {
143144
if (this.undertow != null) {
144145
this.undertow.stop();
146+
Assert.state(this.closeables != null, "'closeables' must not be null");
145147
this.closeables.forEach(this::closeSilently);
146148
}
147149
}
@@ -167,11 +169,12 @@ private Undertow createUndertowServer() {
167169
return this.builder.build();
168170
}
169171

170-
protected HttpHandler createHttpHandler() {
172+
protected @Nullable HttpHandler createHttpHandler() {
171173
HttpHandler handler = null;
172174
for (HttpHandlerFactory factory : this.httpHandlerFactories) {
173175
handler = factory.getHandler(handler);
174176
if (handler instanceof Closeable closeable) {
177+
Assert.state(this.closeables != null, "'closeables' must not be null");
175178
this.closeables.add(closeable);
176179
}
177180
if (handler instanceof GracefulShutdownHandler shutdownHandler) {
@@ -220,11 +223,14 @@ private List<Port> getActualPorts() {
220223
@SuppressWarnings("unchecked")
221224
private List<BoundChannel> extractChannels() {
222225
Field channelsField = ReflectionUtils.findField(Undertow.class, "channels");
226+
Assert.state(channelsField != null, "'channelsField' must not be null");
223227
ReflectionUtils.makeAccessible(channelsField);
224-
return (List<BoundChannel>) ReflectionUtils.getField(channelsField, this.undertow);
228+
List<BoundChannel> channels = (List<BoundChannel>) ReflectionUtils.getField(channelsField, this.undertow);
229+
Assert.state(channels != null, "'channels' must not be null");
230+
return channels;
225231
}
226232

227-
private UndertowWebServer.Port getPortFromChannel(BoundChannel channel) {
233+
private UndertowWebServer.@Nullable Port getPortFromChannel(BoundChannel channel) {
228234
SocketAddress socketAddress = channel.getLocalAddress();
229235
if (socketAddress instanceof InetSocketAddress inetSocketAddress) {
230236
Field sslField = ReflectionUtils.findField(channel.getClass(), "ssl");
@@ -253,20 +259,37 @@ private List<UndertowWebServer.Port> getConfiguredPorts() {
253259
@SuppressWarnings("unchecked")
254260
private List<Object> extractListeners() {
255261
Field listenersField = ReflectionUtils.findField(Undertow.class, "listeners");
262+
Assert.state(listenersField != null, "'listenersField' must not be null");
256263
ReflectionUtils.makeAccessible(listenersField);
257-
return (List<Object>) ReflectionUtils.getField(listenersField, this.undertow);
264+
List<Object> listeners = (List<Object>) ReflectionUtils.getField(listenersField, this.undertow);
265+
Assert.state(listeners != null, "'listeners' must not be null");
266+
return listeners;
258267
}
259268

260269
private UndertowWebServer.Port getPortFromListener(Object listener) {
261270
Field typeField = ReflectionUtils.findField(listener.getClass(), "type");
262-
ReflectionUtils.makeAccessible(typeField);
263-
String protocol = ReflectionUtils.getField(typeField, listener).toString();
271+
Assert.state(typeField != null, "'typeField' must not be null");
272+
String protocol = getProtocol(listener, typeField);
264273
Field portField = ReflectionUtils.findField(listener.getClass(), "port");
265-
ReflectionUtils.makeAccessible(portField);
266-
int port = (Integer) ReflectionUtils.getField(portField, listener);
274+
Assert.state(portField != null, "'portField' must not be null");
275+
int port = getPort(listener, portField);
267276
return new UndertowWebServer.Port(port, protocol);
268277
}
269278

279+
private static Integer getPort(Object listener, Field portField) {
280+
ReflectionUtils.makeAccessible(portField);
281+
Integer value = (Integer) ReflectionUtils.getField(portField, listener);
282+
Assert.state(value != null, "'value' must not be null");
283+
return value;
284+
}
285+
286+
private String getProtocol(Object listener, Field typeField) {
287+
ReflectionUtils.makeAccessible(typeField);
288+
Object value = ReflectionUtils.getField(typeField, listener);
289+
Assert.state(value != null, "'value' must not be null");
290+
return value.toString();
291+
}
292+
270293
@Override
271294
public void stop() throws WebServerException {
272295
synchronized (this.monitor) {
@@ -278,9 +301,12 @@ public void stop() throws WebServerException {
278301
notifyGracefulCallback(false);
279302
}
280303
try {
281-
this.undertow.stop();
282-
for (Closeable closeable : this.closeables) {
283-
closeable.close();
304+
if (this.undertow != null) {
305+
this.undertow.stop();
306+
Assert.state(this.closeables != null, "'closeables' must not be null");
307+
for (Closeable closeable : this.closeables) {
308+
closeable.close();
309+
}
284310
}
285311
}
286312
catch (Exception ex) {
@@ -304,7 +330,7 @@ public int getPort() {
304330
* @return the Undertow server or {@code null} if the server hasn't been started yet
305331
* @since 4.0.0
306332
*/
307-
public Undertow getUndertow() {
333+
public @Nullable Undertow getUndertow() {
308334
return this.undertow;
309335
}
310336

@@ -396,27 +422,30 @@ public String toString() {
396422
*/
397423
private static final class CloseableHttpHandlerFactory implements HttpHandlerFactory {
398424

399-
private final Closeable closeable;
425+
private final @Nullable Closeable closeable;
400426

401-
private CloseableHttpHandlerFactory(Closeable closeable) {
427+
private CloseableHttpHandlerFactory(@Nullable Closeable closeable) {
402428
this.closeable = closeable;
403429
}
404430

405431
@Override
406-
public HttpHandler getHandler(HttpHandler next) {
407-
if (this.closeable == null) {
432+
public @Nullable HttpHandler getHandler(@Nullable HttpHandler next) {
433+
Closeable closeable = this.closeable;
434+
if (closeable == null) {
408435
return next;
409436
}
410437
return new CloseableHttpHandler() {
411438

412439
@Override
413440
public void handleRequest(HttpServerExchange exchange) throws Exception {
414-
next.handleRequest(exchange);
441+
if (next != null) {
442+
next.handleRequest(exchange);
443+
}
415444
}
416445

417446
@Override
418447
public void close() throws IOException {
419-
CloseableHttpHandlerFactory.this.closeable.close();
448+
closeable.close();
420449
}
421450

422451
};
@@ -438,7 +467,7 @@ private interface CloseableHttpHandler extends HttpHandler, Closeable {
438467
static class UndertowWebServerRuntimeHints implements RuntimeHintsRegistrar {
439468

440469
@Override
441-
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
470+
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
442471
hints.reflection()
443472
.registerTypeIfPresent(classLoader, "io.undertow.Undertow",
444473
(hint) -> hint.withField("listeners").withField("channels"));

0 commit comments

Comments
 (0)