Deprecate ListenableFuture in favor of CompletableFuture
This commit deprecates ListenableFuture in favor of CompletableFuture. ListenableFuture was introduced in Spring Framework 4.0, when CompletableFuture was not yet available. Spring now requires JDK 17, so having our own type no longer seems necessary. Major changes in this commit include: - Deprecation of ListenableFuture and related types (ListenableFutureCallback, SettableListenableFuture, etc.) - Deprecation of AsyncListenableTaskExecutor in favor of default methods in AsyncTaskExecutor (submitCompletable). - AsyncHandlerMethodReturnValueHandler now has toCompletableFuture instead of toListenableFuture. - WebSocketClient now has execute methods, which do the same as doHandshake, but return CompletableFutures (cf. the reactive WebSocketClient). All other changes - add an overloaded method that takes a CompletableFuture parameter instead of ListenableFuture, and/or - add a method with a 'Async' suffix that returns a CompletableFuture instead of a ListenableFuture (connectAsync, sendAsync). Closes gh-27780
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -535,6 +535,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
|
||||
@Controller
|
||||
@MessageMapping("listenable-future")
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class ListenableFutureController {
|
||||
|
||||
private ListenableFutureTask<String> future;
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -45,7 +46,6 @@ import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -90,9 +90,9 @@ public class DefaultStompSessionTests {
|
||||
new CompositeMessageConverter(
|
||||
Arrays.asList(new StringMessageConverter(), new ByteArrayMessageConverter())));
|
||||
|
||||
SettableListenableFuture<Void> future = new SettableListenableFuture<>();
|
||||
future.set(null);
|
||||
given(this.connection.send(this.messageCaptor.capture())).willReturn(future);
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.complete(null);
|
||||
given(this.connection.sendAsync(this.messageCaptor.capture())).willReturn(future);
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ public class DefaultStompSessionTests {
|
||||
@Test
|
||||
public void heartbeatNotSupportedByServer() {
|
||||
this.session.afterConnected(this.connection);
|
||||
verify(this.connection).send(any());
|
||||
verify(this.connection).sendAsync(any());
|
||||
|
||||
this.connectHeaders.setHeartbeat(new long[] {10000, 10000});
|
||||
|
||||
@@ -193,7 +193,7 @@ public class DefaultStompSessionTests {
|
||||
@Test
|
||||
public void heartbeatTasks() {
|
||||
this.session.afterConnected(this.connection);
|
||||
verify(this.connection).send(any());
|
||||
verify(this.connection).sendAsync(any());
|
||||
|
||||
this.connectHeaders.setHeartbeat(new long[] {10000, 10000});
|
||||
|
||||
@@ -216,7 +216,7 @@ public class DefaultStompSessionTests {
|
||||
writeTask.run();
|
||||
StompHeaderAccessor accessor = StompHeaderAccessor.createForHeartbeat();
|
||||
Message<byte[]> message = MessageBuilder.createMessage(new byte[] {'\n'}, accessor.getMessageHeaders());
|
||||
verify(this.connection).send(eq(message));
|
||||
verify(this.connection).sendAsync(eq(message));
|
||||
verifyNoMoreInteractions(this.connection);
|
||||
|
||||
reset(this.sessionHandler);
|
||||
@@ -435,10 +435,9 @@ public class DefaultStompSessionTests {
|
||||
assertThat(this.session.isConnected()).isTrue();
|
||||
|
||||
IllegalStateException exception = new IllegalStateException("simulated exception");
|
||||
SettableListenableFuture<Void> future = new SettableListenableFuture<>();
|
||||
future.setException(exception);
|
||||
CompletableFuture<Void> future = CompletableFuture.failedFuture(exception);
|
||||
|
||||
given(this.connection.send(any())).willReturn(future);
|
||||
given(this.connection.sendAsync(any())).willReturn(future);
|
||||
assertThatExceptionOfType(MessageDeliveryException.class).isThrownBy(() ->
|
||||
this.session.send("/topic/foo", "sample payload".getBytes(StandardCharsets.UTF_8)))
|
||||
.withCause(exception);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -38,7 +39,6 @@ import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.messaging.simp.stomp.StompSession.Subscription;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -107,10 +107,10 @@ public class ReactorNettyTcpStompClientTests {
|
||||
public void publishSubscribe() throws Exception {
|
||||
String destination = "/topic/foo";
|
||||
ConsumingHandler consumingHandler1 = new ConsumingHandler(destination);
|
||||
ListenableFuture<StompSession> consumerFuture1 = this.client.connect(consumingHandler1);
|
||||
CompletableFuture<StompSession> consumerFuture1 = this.client.connectAsync(consumingHandler1);
|
||||
|
||||
ConsumingHandler consumingHandler2 = new ConsumingHandler(destination);
|
||||
ListenableFuture<StompSession> consumerFuture2 = this.client.connect(consumingHandler2);
|
||||
CompletableFuture<StompSession> consumerFuture2 = this.client.connectAsync(consumingHandler2);
|
||||
|
||||
assertThat(consumingHandler1.awaitForSubscriptions(5000)).isTrue();
|
||||
assertThat(consumingHandler2.awaitForSubscriptions(5000)).isTrue();
|
||||
@@ -118,7 +118,7 @@ public class ReactorNettyTcpStompClientTests {
|
||||
ProducingHandler producingHandler = new ProducingHandler();
|
||||
producingHandler.addToSend(destination, "foo1");
|
||||
producingHandler.addToSend(destination, "foo2");
|
||||
ListenableFuture<StompSession> producerFuture = this.client.connect(producingHandler);
|
||||
CompletableFuture<StompSession> producerFuture = this.client.connectAsync(producingHandler);
|
||||
|
||||
assertThat(consumingHandler1.awaitForMessageCount(2, 5000)).isTrue();
|
||||
assertThat(consumingHandler1.getReceived()).containsExactly("foo1", "foo2");
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -39,8 +40,6 @@ import org.springframework.messaging.tcp.TcpConnection;
|
||||
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
||||
import org.springframework.messaging.tcp.TcpOperations;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -309,10 +308,8 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
|
||||
private static ListenableFutureTask<Void> getVoidFuture() {
|
||||
ListenableFutureTask<Void> futureTask = new ListenableFutureTask<>(() -> null);
|
||||
futureTask.run();
|
||||
return futureTask;
|
||||
private static CompletableFuture<Void> getVoidFuture() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -336,21 +333,22 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> handler) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<byte[]> handler) {
|
||||
this.connectionHandler = handler;
|
||||
handler.afterConnected(this.connection);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> handler, ReconnectStrategy strategy) {
|
||||
public CompletableFuture<Void> connectAsync(TcpConnectionHandler<byte[]> handler,
|
||||
ReconnectStrategy reconnectStrategy) {
|
||||
this.connectionHandler = handler;
|
||||
handler.afterConnected(this.connection);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> shutdown() {
|
||||
public CompletableFuture<Void> shutdownAsync() {
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
@@ -371,7 +369,7 @@ class StompBrokerRelayMessageHandlerTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> send(Message<byte[]> message) {
|
||||
public CompletableFuture<Void> sendAsync(Message<byte[]> message) {
|
||||
this.messages.add(message);
|
||||
return getVoidFuture();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user