diff --git a/gradle/spring-module.gradle b/gradle/spring-module.gradle index 09755cdac4a0..95886e677e02 100644 --- a/gradle/spring-module.gradle +++ b/gradle/spring-module.gradle @@ -105,6 +105,10 @@ tasks.register('javadocJar', Jar) { from javadoc } +nullability { + nullAwayVersion = "0.12.15" +} + publishing { publications { mavenJava(MavenPublication) { diff --git a/spring-core/src/main/java/org/springframework/core/codec/Decoder.java b/spring-core/src/main/java/org/springframework/core/codec/Decoder.java index 410a3c3a4643..92584a009743 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/Decoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/Decoder.java @@ -93,7 +93,7 @@ Mono decodeToMono(Publisher inputStream, ResolvableType elementTy default @Nullable T decode(DataBuffer buffer, ResolvableType targetType, @Nullable MimeType mimeType, @Nullable Map hints) throws DecodingException { - CompletableFuture future = decodeToMono(Mono.just(buffer), targetType, mimeType, hints).toFuture(); + CompletableFuture<@Nullable T> future = decodeToMono(Mono.just(buffer), targetType, mimeType, hints).toFuture(); Assert.state(future.isDone(), "DataBuffer decoding should have completed"); try { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java index 14c0bdbdacc7..1c6514ab3cdd 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java @@ -96,7 +96,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler private static final byte[] EMPTY_PAYLOAD = new byte[0]; - private static final CompletableFuture EMPTY_TASK = CompletableFuture.completedFuture(null); + private static final CompletableFuture<@Nullable Void> EMPTY_TASK = CompletableFuture.completedFuture(null); private static final StompHeaderAccessor HEART_BEAT_ACCESSOR; @@ -851,7 +851,7 @@ public void afterConnectionClosed() { * @return a future to wait for the result */ @SuppressWarnings("unchecked") - public CompletableFuture forward(final Message message, final StompHeaderAccessor accessor) { + public CompletableFuture<@Nullable Void> forward(final Message message, final StompHeaderAccessor accessor) { TcpConnection conn = this.tcpConnection; if (!this.isStompConnected || conn == null) { @@ -887,7 +887,7 @@ else if (logger.isTraceEnabled()) { logger.trace("Forwarding " + accessor.getDetailedLogMessage(message.getPayload())); } - CompletableFuture future = conn.sendAsync((Message) messageToSend); + CompletableFuture<@Nullable Void> future = conn.sendAsync((Message) messageToSend); future.whenComplete((unused, throwable) -> { if (throwable == null) { if (accessor.getCommand() == StompCommand.DISCONNECT) { @@ -1067,9 +1067,9 @@ public void afterConnectionClosed() { } @Override - public CompletableFuture forward(Message message, StompHeaderAccessor accessor) { + public CompletableFuture<@Nullable Void> forward(Message message, StompHeaderAccessor accessor) { try { - CompletableFuture future = super.forward(message, accessor); + CompletableFuture<@Nullable Void> future = super.forward(message, accessor); if (message.getHeaders().get(SimpMessageHeaderAccessor.IGNORE_ERROR) == null) { future.get(); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpConnection.java b/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpConnection.java index 21b0a114011b..5c6b8ef68231 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpConnection.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpConnection.java @@ -19,6 +19,8 @@ import java.io.Closeable; import java.util.concurrent.CompletableFuture; +import org.jspecify.annotations.Nullable; + import org.springframework.messaging.Message; /** @@ -37,7 +39,7 @@ public interface TcpConnection

extends Closeable { * message was successfully sent * @since 6.0 */ - CompletableFuture sendAsync(Message

message); + CompletableFuture<@Nullable Void> sendAsync(Message

message); /** * Register a task to invoke after a period of read inactivity. diff --git a/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpOperations.java b/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpOperations.java index 4dcaa0f02970..f13f5ff409e4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpOperations.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/tcp/TcpOperations.java @@ -18,6 +18,9 @@ import java.util.concurrent.CompletableFuture; +import org.jspecify.annotations.Nullable; + + /** * A contract for establishing TCP connections. * @@ -34,7 +37,7 @@ public interface TcpOperations

{ * connection is successfully established * @since 6.0 */ - CompletableFuture connectAsync(TcpConnectionHandler

connectionHandler); + CompletableFuture<@Nullable Void> connectAsync(TcpConnectionHandler

connectionHandler); /** * Open a new connection and a strategy for reconnecting if the connection fails. @@ -44,7 +47,7 @@ public interface TcpOperations

{ * initial connection is successfully established * @since 6.0 */ - CompletableFuture connectAsync(TcpConnectionHandler

connectionHandler, ReconnectStrategy reconnectStrategy); + CompletableFuture<@Nullable Void> connectAsync(TcpConnectionHandler

connectionHandler, ReconnectStrategy reconnectStrategy); /** * Shut down and close any open connections. @@ -52,6 +55,6 @@ public interface TcpOperations

{ * connection is successfully closed * @since 6.0 */ - CompletableFuture shutdownAsync(); + CompletableFuture<@Nullable Void> shutdownAsync(); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpClient.java b/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpClient.java index 5a03e3b1f3a9..8be8726134fd 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpClient.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpClient.java @@ -172,7 +172,7 @@ public Log getLogger() { @Override - public CompletableFuture connectAsync(TcpConnectionHandler

handler) { + public CompletableFuture<@Nullable Void> connectAsync(TcpConnectionHandler

handler) { Assert.notNull(handler, "TcpConnectionHandler is required"); if (this.stopping) { @@ -200,7 +200,7 @@ protected TcpClient extendTcpClient(TcpClient tcpClient, TcpConnectionHandler

} @Override - public CompletableFuture connectAsync(TcpConnectionHandler

handler, ReconnectStrategy strategy) { + public CompletableFuture<@Nullable Void> connectAsync(TcpConnectionHandler

handler, ReconnectStrategy strategy) { Assert.notNull(handler, "TcpConnectionHandler is required"); Assert.notNull(strategy, "ReconnectStrategy is required"); @@ -209,7 +209,7 @@ public CompletableFuture connectAsync(TcpConnectionHandler

handler, Rec } // Report first connect to the ListenableFuture - CompletableFuture connectFuture = new CompletableFuture<>(); + CompletableFuture<@Nullable Void> connectFuture = new CompletableFuture<>(); extendTcpClient(this.tcpClient, handler) .handle(new ReactorNettyHandler(handler)) @@ -228,7 +228,7 @@ public CompletableFuture connectAsync(TcpConnectionHandler

handler, Rec return connectFuture; } - private CompletableFuture handleShuttingDownConnectFailure(TcpConnectionHandler

handler) { + private CompletableFuture<@Nullable Void> handleShuttingDownConnectFailure(TcpConnectionHandler

handler) { IllegalStateException ex = new IllegalStateException("Shutting down."); handler.afterConnectFailure(ex); return Mono.error(ex).toFuture(); @@ -240,7 +240,7 @@ private Publisher reconnect(Integer attempt, ReconnectStrategy r } @Override - public CompletableFuture shutdownAsync() { + public CompletableFuture<@Nullable Void> shutdownAsync() { if (this.stopping) { return CompletableFuture.completedFuture(null); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpConnection.java b/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpConnection.java index 79655783501b..12b54bfb1dd4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpConnection.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/tcp/reactor/ReactorNettyTcpConnection.java @@ -19,6 +19,7 @@ import java.util.concurrent.CompletableFuture; import io.netty.buffer.ByteBuf; +import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; import reactor.core.publisher.Sinks; import reactor.netty.NettyInbound; @@ -56,7 +57,7 @@ public ReactorNettyTcpConnection(NettyInbound inbound, NettyOutbound outbound, @Override - public CompletableFuture sendAsync(Message

message) { + public CompletableFuture<@Nullable Void> sendAsync(Message

message) { ByteBuf byteBuf = this.outbound.alloc().buffer(); this.codec.encode(message, byteBuf); return this.outbound.send(Mono.just(byteBuf)) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java index 08dc35d82f4f..0d40b408a371 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java @@ -100,7 +100,7 @@ public ParameterNameDiscoverer getParameterNameDiscoverer() { public @Nullable HandlerResult invokeForHandlerResult(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) { - CompletableFuture future = + CompletableFuture<@Nullable HandlerResult> future = this.delegate.invoke(exchange, bindingContext, providedArgs).toFuture(); if (!future.isDone()) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java index 36740d1fb3d4..ded54a9e0ad7 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java @@ -387,9 +387,9 @@ public boolean supportsPartialMessages() { // TcpConnection implementation @Override - public CompletableFuture sendAsync(Message message) { + public CompletableFuture<@Nullable Void> sendAsync(Message message) { updateLastWriteTime(); - CompletableFuture future = new CompletableFuture<>(); + CompletableFuture<@Nullable Void> future = new CompletableFuture<>(); try { WebSocketSession session = this.session; Assert.state(session != null, "No WebSocketSession available");