diff --git a/build.gradle b/build.gradle index 8b1dbb61c12..4036e6a263c 100644 --- a/build.gradle +++ b/build.gradle @@ -114,7 +114,7 @@ ext { springKafkaVersion = '3.3.0-SNAPSHOT' springRetryVersion = '2.0.10' springSecurityVersion = '6.4.0-SNAPSHOT' - springVersion = '6.2.0-RC2' + springVersion = '6.2.0-SNAPSHOT' springWsVersion = '4.0.11' testcontainersVersion = '1.20.3' tomcatVersion = '10.1.31' diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index 9d5e0610d79..1b3773ae477 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -363,9 +363,9 @@ public void setShouldTrack(boolean shouldTrack) { /** * Set the executor for use when the gateway method returns - * {@link java.util.concurrent.Future} or {@link org.springframework.util.concurrent.ListenableFuture}. + * {@link Future} or {@link CompletableFuture}. * Set it to null to disable the async processing, and any - * {@link java.util.concurrent.Future} return types must be returned by the downstream flow. + * {@link Future} return types must be returned by the downstream flow. * @param executor The executor. */ public void setAsyncExecutor(@Nullable Executor executor) { @@ -522,7 +522,7 @@ public T getObject() { @Override @Nullable - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") public Object invoke(final MethodInvocation invocation) throws Throwable { // NOSONAR Method method = invocation.getMethod(); Class returnType; @@ -542,6 +542,9 @@ else if (CompletableFuture.class.equals(returnType)) { // exact return CompletableFuture.supplyAsync(invoker, this.asyncExecutor); } else if (org.springframework.util.concurrent.ListenableFuture.class.equals(returnType)) { + logger.warn("The 'org.springframework.util.concurrent.ListenableFuture' is deprecated for removal." + + "The 'CompletableFuture' is recommended to be used instead." + + "The 'ListenableFuture' support will be removed in Spring Integration 7.0."); return ((org.springframework.core.task.AsyncListenableTaskExecutor) this.asyncExecutor) .submitListenable(invoker::get); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java index 5f72bd7e7bc..7dd30e4520b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java @@ -71,7 +71,7 @@ * @author Marius Bogoevici * @author Ngoc Nhan * - * since 4.1 + * @since 4.1 */ public abstract class AbstractMessageProducingHandler extends AbstractMessageHandler implements MessageProducer, HeaderPropagationAware { @@ -321,7 +321,7 @@ else if (reply instanceof AbstractIntegrationMessageBuilder) { return replyChannel; } - @SuppressWarnings("deprecation") + @SuppressWarnings("removal") private void doProduceOutput(Message requestMessage, MessageHeaders requestHeaders, Object reply, @Nullable Object replyChannelArg) { @@ -361,7 +361,7 @@ private void doProduceOutput(Message requestMessage, MessageHeaders requestHe sendOutput(createOutputMessage(reply, requestHeaders), replyChannel, false); } - private static Publisher toPublisherReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) { + private Publisher toPublisherReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) { if (reactiveAdapter != null) { return reactiveAdapter.toPublisher(reply); } @@ -371,7 +371,7 @@ private static Publisher toPublisherReply(Object reply, @Nullable ReactiveAda } @SuppressWarnings("try") - private static CompletableFuture toFutureReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) { + private CompletableFuture toFutureReply(Object reply, @Nullable ReactiveAdapter reactiveAdapter) { if (reactiveAdapter != null) { Mono reactiveReply; Publisher publisher = reactiveAdapter.toPublisher(reply); @@ -419,12 +419,15 @@ via whenComplete() callback. So, when value is set into the Future, it is availa } } - @SuppressWarnings("deprecation") - private static CompletableFuture toCompletableFuture(Object reply) { - if (reply instanceof CompletableFuture) { - return (CompletableFuture) reply; + @SuppressWarnings("removal") + private CompletableFuture toCompletableFuture(Object reply) { + if (reply instanceof CompletableFuture completableFuture) { + return completableFuture; } else { + logger.warn("The 'org.springframework.util.concurrent.ListenableFuture' is deprecated for removal." + + "The 'CompletableFuture' is recommended to be used instead." + + "The 'ListenableFuture' support will be removed in Spring Integration 7.0."); return ((org.springframework.util.concurrent.ListenableFuture) reply).completable(); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java index c8c156e8e1b..e744c673551 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java @@ -444,14 +444,6 @@ public void testExecs() throws Exception { assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); assertThat(result2.get().getName()).startsWith("exec-"); - org.springframework.util.concurrent.ListenableFuture result3 = - this.execGateway.test3(Thread.currentThread()); - final CountDownLatch latch1 = new CountDownLatch(1); - result3.addCallback(data -> latch1.countDown(), ex -> { - }); - assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue(); - assertThat(result3.get().getName()).startsWith("exec-"); - /* @IntegrationComponentScan(useDefaultFilters = false, includeFilters = @ComponentScan.Filter(TestMessagingGateway.class)) @@ -770,10 +762,6 @@ public interface ExecGateway { @Gateway(requestChannel = "gatewayThreadChannel") CompletableFuture test2(Thread caller); - @Gateway(requestChannel = "gatewayThreadChannel") - @SuppressWarnings("deprecation") - org.springframework.util.concurrent.ListenableFuture test3(Thread caller); - } @MessagingGateway(name = "noExecutorGateway", asyncExecutor = AnnotationConstants.NULL) diff --git a/spring-integration-rsocket/src/main/java/org/springframework/integration/rsocket/outbound/RSocketOutboundGateway.java b/spring-integration-rsocket/src/main/java/org/springframework/integration/rsocket/outbound/RSocketOutboundGateway.java index 95b3f5bf554..002fa0e45bc 100644 --- a/spring-integration-rsocket/src/main/java/org/springframework/integration/rsocket/outbound/RSocketOutboundGateway.java +++ b/spring-integration-rsocket/src/main/java/org/springframework/integration/rsocket/outbound/RSocketOutboundGateway.java @@ -50,18 +50,18 @@ *

* An RSocket operation is determined by the configured {@link RSocketInteractionModel} or respective SpEL * expression to be evaluated at runtime against the request message. - * By default the {@link RSocketInteractionModel#requestResponse} operation is used. + * By default, the {@link RSocketInteractionModel#requestResponse} operation is used. *

* For a {@link Publisher}-based requests, it must be present in the request message {@code payload}. * The flattening via upstream {@link org.springframework.integration.channel.FluxMessageChannel} will work, too, * but this way we will lose a scope of particular request and every {@link Publisher} event - * will be send in its own plain request. + * will be sent in its own plain request. *

* If reply is a {@link reactor.core.publisher.Flux}, it is wrapped to the {@link Mono} to retain a request scope. * The downstream flow is responsible to obtain this {@link reactor.core.publisher.Flux} from a message payload * and subscribe to it by itself. The {@link Mono} reply from this component is subscribed from the downstream * {@link org.springframework.integration.channel.FluxMessageChannel} or it is adapted to the - * {@link org.springframework.util.concurrent.ListenableFuture} otherwise. + * {@link java.util.concurrent.CompletableFuture} otherwise. * * @author Artem Bilan * diff --git a/spring-integration-stomp/src/main/java/org/springframework/integration/stomp/AbstractStompSessionManager.java b/spring-integration-stomp/src/main/java/org/springframework/integration/stomp/AbstractStompSessionManager.java index d4233b4ce1a..5c2913af683 100644 --- a/spring-integration-stomp/src/main/java/org/springframework/integration/stomp/AbstractStompSessionManager.java +++ b/spring-integration-stomp/src/main/java/org/springframework/integration/stomp/AbstractStompSessionManager.java @@ -49,11 +49,10 @@ import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; -import org.springframework.util.concurrent.ListenableFuture; /** * Base {@link StompSessionManager} implementation to manage a single {@link StompSession} - * over its {@link ListenableFuture} from the target implementation of this class. + * over its {@link CompletableFuture} from the target implementation of this class. *

* The connection to the {@link StompSession} is made during {@link #start()}. *

diff --git a/src/reference/antora/modules/ROOT/pages/gateway.adoc b/src/reference/antora/modules/ROOT/pages/gateway.adoc index d25c309e3d2..367f0abf487 100644 --- a/src/reference/antora/modules/ROOT/pages/gateway.adoc +++ b/src/reference/antora/modules/ROOT/pages/gateway.adoc @@ -618,9 +618,6 @@ There are two modes of operation when returning this type: * 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. In this scenario, the downstream flow is expected to return a `CompletableFuture` of the appropriate type. -NOTE: The `org.springframework.util.concurrent.ListenableFuture` has been deprecated starting with Spring Framework `6.0`. -It is recommended now to migrate to the `CompletableFuture` which provides similar processing functionality. - [[usage-scenarios]] ==== Usage Scenarios