Skip to content

Commit b50c402

Browse files
committed
GH-9617: @SuppressWarnings("removal") for ListenableFuture
Fixes: #9617 Issue link: #9617 The `ListenableFuture` is marked `forRemoval` in Spring Framework. So, fix the code base to use `@SuppressWarnings("removal")`. Also, add a warning into logs that `ListenableFuture` support will be removed in `7.0`. * Fix JavaDocs where `ListenableFuture` is mentioned in favor of `CompletableFuture`
1 parent f423280 commit b50c402

File tree

7 files changed

+22
-32
lines changed

7 files changed

+22
-32
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ ext {
114114
springKafkaVersion = '3.3.0-SNAPSHOT'
115115
springRetryVersion = '2.0.10'
116116
springSecurityVersion = '6.4.0-SNAPSHOT'
117-
springVersion = '6.2.0-RC2'
117+
springVersion = '6.2.0-SNAPSHOT'
118118
springWsVersion = '4.0.11'
119119
testcontainersVersion = '1.20.3'
120120
tomcatVersion = '10.1.31'

spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ public void setShouldTrack(boolean shouldTrack) {
363363

364364
/**
365365
* Set the executor for use when the gateway method returns
366-
* {@link java.util.concurrent.Future} or {@link org.springframework.util.concurrent.ListenableFuture}.
366+
* {@link Future} or {@link CompletableFuture}.
367367
* Set it to null to disable the async processing, and any
368-
* {@link java.util.concurrent.Future} return types must be returned by the downstream flow.
368+
* {@link Future} return types must be returned by the downstream flow.
369369
* @param executor The executor.
370370
*/
371371
public void setAsyncExecutor(@Nullable Executor executor) {
@@ -522,7 +522,7 @@ public T getObject() {
522522

523523
@Override
524524
@Nullable
525-
@SuppressWarnings("deprecation")
525+
@SuppressWarnings("removal")
526526
public Object invoke(final MethodInvocation invocation) throws Throwable { // NOSONAR
527527
Method method = invocation.getMethod();
528528
Class<?> returnType;
@@ -542,6 +542,9 @@ else if (CompletableFuture.class.equals(returnType)) { // exact
542542
return CompletableFuture.supplyAsync(invoker, this.asyncExecutor);
543543
}
544544
else if (org.springframework.util.concurrent.ListenableFuture.class.equals(returnType)) {
545+
logger.warn("The 'org.springframework.util.concurrent.ListenableFuture' is deprecated for removal." +
546+
"The 'CompletableFuture' is recommended to be used instead." +
547+
"The 'ListenableFuture' support will be removed in Spring Integration 7.0.");
545548
return ((org.springframework.core.task.AsyncListenableTaskExecutor) this.asyncExecutor)
546549
.submitListenable(invoker::get);
547550
}

spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
* @author Marius Bogoevici
7272
* @author Ngoc Nhan
7373
*
74-
* since 4.1
74+
* @since 4.1
7575
*/
7676
public abstract class AbstractMessageProducingHandler extends AbstractMessageHandler
7777
implements MessageProducer, HeaderPropagationAware {
@@ -321,7 +321,7 @@ else if (reply instanceof AbstractIntegrationMessageBuilder<?>) {
321321
return replyChannel;
322322
}
323323

324-
@SuppressWarnings("deprecation")
324+
@SuppressWarnings("removal")
325325
private void doProduceOutput(Message<?> requestMessage, MessageHeaders requestHeaders, Object reply,
326326
@Nullable Object replyChannelArg) {
327327

@@ -361,7 +361,7 @@ private void doProduceOutput(Message<?> requestMessage, MessageHeaders requestHe
361361
sendOutput(createOutputMessage(reply, requestHeaders), replyChannel, false);
362362
}
363363

364-
private static Publisher<?> toPublisherReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) {
364+
private Publisher<?> toPublisherReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) {
365365
if (reactiveAdapter != null) {
366366
return reactiveAdapter.toPublisher(reply);
367367
}
@@ -371,7 +371,7 @@ private static Publisher<?> toPublisherReply(Object reply, @Nullable ReactiveAda
371371
}
372372

373373
@SuppressWarnings("try")
374-
private static CompletableFuture<?> toFutureReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) {
374+
private CompletableFuture<?> toFutureReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) {
375375
if (reactiveAdapter != null) {
376376
Mono<?> reactiveReply;
377377
Publisher<?> publisher = reactiveAdapter.toPublisher(reply);
@@ -419,12 +419,15 @@ via whenComplete() callback. So, when value is set into the Future, it is availa
419419
}
420420
}
421421

422-
@SuppressWarnings("deprecation")
423-
private static CompletableFuture<?> toCompletableFuture(Object reply) {
424-
if (reply instanceof CompletableFuture<?>) {
425-
return (CompletableFuture<?>) reply;
422+
@SuppressWarnings("removal")
423+
private CompletableFuture<?> toCompletableFuture(Object reply) {
424+
if (reply instanceof CompletableFuture<?> completableFuture) {
425+
return completableFuture;
426426
}
427427
else {
428+
logger.warn("The 'org.springframework.util.concurrent.ListenableFuture' is deprecated for removal." +
429+
"The 'CompletableFuture' is recommended to be used instead." +
430+
"The 'ListenableFuture' support will be removed in Spring Integration 7.0.");
428431
return ((org.springframework.util.concurrent.ListenableFuture<?>) reply).completable();
429432
}
430433
}

spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -444,14 +444,6 @@ public void testExecs() throws Exception {
444444
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
445445
assertThat(result2.get().getName()).startsWith("exec-");
446446

447-
org.springframework.util.concurrent.ListenableFuture<Thread> result3 =
448-
this.execGateway.test3(Thread.currentThread());
449-
final CountDownLatch latch1 = new CountDownLatch(1);
450-
result3.addCallback(data -> latch1.countDown(), ex -> {
451-
});
452-
assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue();
453-
assertThat(result3.get().getName()).startsWith("exec-");
454-
455447
/*
456448
@IntegrationComponentScan(useDefaultFilters = false,
457449
includeFilters = @ComponentScan.Filter(TestMessagingGateway.class))
@@ -770,10 +762,6 @@ public interface ExecGateway {
770762
@Gateway(requestChannel = "gatewayThreadChannel")
771763
CompletableFuture<Thread> test2(Thread caller);
772764

773-
@Gateway(requestChannel = "gatewayThreadChannel")
774-
@SuppressWarnings("deprecation")
775-
org.springframework.util.concurrent.ListenableFuture<Thread> test3(Thread caller);
776-
777765
}
778766

779767
@MessagingGateway(name = "noExecutorGateway", asyncExecutor = AnnotationConstants.NULL)

spring-integration-rsocket/src/main/java/org/springframework/integration/rsocket/outbound/RSocketOutboundGateway.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,18 @@
5050
* <p>
5151
* An RSocket operation is determined by the configured {@link RSocketInteractionModel} or respective SpEL
5252
* expression to be evaluated at runtime against the request message.
53-
* By default the {@link RSocketInteractionModel#requestResponse} operation is used.
53+
* By default, the {@link RSocketInteractionModel#requestResponse} operation is used.
5454
* <p>
5555
* For a {@link Publisher}-based requests, it must be present in the request message {@code payload}.
5656
* The flattening via upstream {@link org.springframework.integration.channel.FluxMessageChannel} will work, too,
5757
* but this way we will lose a scope of particular request and every {@link Publisher} event
58-
* will be send in its own plain request.
58+
* will be sent in its own plain request.
5959
* <p>
6060
* If reply is a {@link reactor.core.publisher.Flux}, it is wrapped to the {@link Mono} to retain a request scope.
6161
* The downstream flow is responsible to obtain this {@link reactor.core.publisher.Flux} from a message payload
6262
* and subscribe to it by itself. The {@link Mono} reply from this component is subscribed from the downstream
6363
* {@link org.springframework.integration.channel.FluxMessageChannel} or it is adapted to the
64-
* {@link org.springframework.util.concurrent.ListenableFuture} otherwise.
64+
* {@link java.util.concurrent.CompletableFuture} otherwise.
6565
*
6666
* @author Artem Bilan
6767
*

spring-integration-stomp/src/main/java/org/springframework/integration/stomp/AbstractStompSessionManager.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@
4949
import org.springframework.scheduling.TaskScheduler;
5050
import org.springframework.util.Assert;
5151
import org.springframework.util.ObjectUtils;
52-
import org.springframework.util.concurrent.ListenableFuture;
5352

5453
/**
5554
* Base {@link StompSessionManager} implementation to manage a single {@link StompSession}
56-
* over its {@link ListenableFuture} from the target implementation of this class.
55+
* over its {@link CompletableFuture} from the target implementation of this class.
5756
* <p>
5857
* The connection to the {@link StompSession} is made during {@link #start()}.
5958
* <p>

src/reference/antora/modules/ROOT/pages/gateway.adoc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,6 @@ There are two modes of operation when returning this type:
618618
* When the async executor is explicitly set to `null` and the return type is `CompletableFuture` or the return type is a subclass of `CompletableFuture`, the flow is invoked on the caller's thread.
619619
In this scenario, the downstream flow is expected to return a `CompletableFuture` of the appropriate type.
620620

621-
NOTE: The `org.springframework.util.concurrent.ListenableFuture` has been deprecated starting with Spring Framework `6.0`.
622-
It is recommended now to migrate to the `CompletableFuture` which provides similar processing functionality.
623-
624621
[[usage-scenarios]]
625622
==== Usage Scenarios
626623

0 commit comments

Comments
 (0)