Fix deprecations around ListenableFuture (#3865)
* Fix deprecations around ListenableFuture SF has deprecated a `ListenableFuture` and API around it * Migrate to `CompletableFuture` everywhere a `ListenableFuture` has been used * Suppress a deprecation for `ListenableFuture` keeping the functionality until the next version * Resolve deprecations nad removals from the latest Spring for Apache Kafka * Fix documentation for the `ListenableFuture` in favor of `CompletableFuture` NOTE: the AMQP module is left as is until `ListenableFuture` deprecation is resolved in Spring AMQP * * Restore some `ListenableFuture` test for messaging gateway
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -26,7 +26,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -49,7 +48,6 @@ import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.support.TaskExecutorAdapter;
|
||||
@@ -145,10 +143,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
|
||||
private boolean asyncExecutorExplicitlySet;
|
||||
|
||||
private Class<?> asyncSubmitType;
|
||||
|
||||
private Class<?> asyncSubmitListenableType;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private Map<String, GatewayMethodMetadata> methodMetadataMap;
|
||||
@@ -468,15 +462,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
new ProxyFactory(this.serviceInterface, this);
|
||||
gatewayProxyFactory.addAdvice(new DefaultMethodInvokingMethodInterceptor());
|
||||
this.serviceProxy = gatewayProxyFactory.getProxy(this.beanClassLoader);
|
||||
if (this.asyncExecutor != null) {
|
||||
Callable<String> task = () -> null;
|
||||
Future<String> submitType = this.asyncExecutor.submit(task);
|
||||
this.asyncSubmitType = submitType.getClass();
|
||||
if (this.asyncExecutor instanceof AsyncListenableTaskExecutor) {
|
||||
submitType = ((AsyncListenableTaskExecutor) this.asyncExecutor).submitListenable(task);
|
||||
this.asyncSubmitListenableType = submitType.getClass();
|
||||
}
|
||||
}
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
|
||||
this.initialized = true;
|
||||
}
|
||||
@@ -511,6 +496,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
@SuppressWarnings("deprecation")
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable { // NOSONAR
|
||||
final Class<?> returnType;
|
||||
MethodInvocationGateway gateway = this.gatewayMap.get(invocation.getMethod());
|
||||
@@ -522,15 +508,16 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
}
|
||||
if (this.asyncExecutor != null && !Object.class.equals(returnType)) {
|
||||
Invoker invoker = new Invoker(invocation);
|
||||
if (returnType.isAssignableFrom(this.asyncSubmitType)) {
|
||||
if (Future.class.equals(returnType)) {
|
||||
return this.asyncExecutor.submit(invoker::get);
|
||||
}
|
||||
else if (returnType.isAssignableFrom(this.asyncSubmitListenableType)) {
|
||||
return ((AsyncListenableTaskExecutor) this.asyncExecutor).submitListenable(invoker::get);
|
||||
}
|
||||
else if (CompletableFuture.class.equals(returnType)) { // exact
|
||||
return CompletableFuture.supplyAsync(invoker, this.asyncExecutor);
|
||||
}
|
||||
else if (org.springframework.util.concurrent.ListenableFuture.class.equals(returnType)) {
|
||||
return ((org.springframework.core.task.AsyncListenableTaskExecutor) this.asyncExecutor)
|
||||
.submitListenable(invoker::get);
|
||||
}
|
||||
else if (Future.class.isAssignableFrom(returnType)) {
|
||||
logger.debug(() -> "AsyncTaskExecutor submit*() return types are incompatible with the method return " +
|
||||
"type; running on calling thread; the downstream flow must return the required Future: "
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -106,9 +105,9 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow async replies. If the handler reply is a {@link ListenableFuture}, send
|
||||
* the output when it is satisfied rather than sending the future as the result.
|
||||
* Ignored for return types other than {@link ListenableFuture}.
|
||||
* Allow async replies. If the handler reply is a {@link CompletableFuture} or {@link Publisher},
|
||||
* send the output when it is satisfied rather than sending the future as the result.
|
||||
* Ignored for return types other than {@link CompletableFuture} or {@link Publisher}.
|
||||
* @param async true to allow.
|
||||
* @since 4.3
|
||||
*/
|
||||
@@ -299,6 +298,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
return replyChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void doProduceOutput(Message<?> requestMessage, MessageHeaders requestHeaders, Object reply,
|
||||
@Nullable Object replyChannelArg) {
|
||||
|
||||
@@ -307,7 +307,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
replyChannel = getOutputChannel();
|
||||
}
|
||||
|
||||
if (this.async && (reply instanceof ListenableFuture<?>
|
||||
if (this.async && (reply instanceof org.springframework.util.concurrent.ListenableFuture<?>
|
||||
|| reply instanceof CompletableFuture<?>
|
||||
|| reply instanceof Publisher<?>)) {
|
||||
|
||||
@@ -351,13 +351,14 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
return builder;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void asyncNonReactiveReply(Message<?> requestMessage, Object reply, @Nullable Object replyChannel) {
|
||||
CompletableFuture<?> future;
|
||||
if (reply instanceof CompletableFuture<?>) {
|
||||
future = (CompletableFuture<?>) reply;
|
||||
}
|
||||
else if (reply instanceof ListenableFuture<?>) {
|
||||
future = ((ListenableFuture<?>) reply).completable();
|
||||
else if (reply instanceof org.springframework.util.concurrent.ListenableFuture<?>) {
|
||||
future = ((org.springframework.util.concurrent.ListenableFuture<?>) reply).completable();
|
||||
}
|
||||
else {
|
||||
Mono<?> reactiveReply;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -17,10 +17,12 @@
|
||||
package org.springframework.integration.config.annotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -33,9 +35,7 @@ import org.springframework.messaging.MessageDeliveryException;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -44,7 +44,7 @@ import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
* @author Artem Bilan
|
||||
* @author Yilin Wei
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringJUnitConfig
|
||||
@DirtiesContext
|
||||
public class AnnotatedEndpointActivationTests {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class AnnotatedEndpointActivationTests {
|
||||
// them will get the message.
|
||||
private static volatile int count = 0;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void resetCount() {
|
||||
count = 0;
|
||||
}
|
||||
@@ -108,11 +108,12 @@ public class AnnotatedEndpointActivationTests {
|
||||
assertThat(count).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test(expected = MessageDeliveryException.class)
|
||||
@Test
|
||||
@DirtiesContext
|
||||
public void stopContext() {
|
||||
applicationContext.stop();
|
||||
this.input.send(new GenericMessage<>("foo"));
|
||||
assertThatExceptionOfType(MessageDeliveryException.class)
|
||||
.isThrownBy(() -> this.input.send(new GenericMessage<>("foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,9 +160,9 @@ public class AnnotatedEndpointActivationTests {
|
||||
private static class AnnotatedEndpoint3 {
|
||||
|
||||
@ServiceActivator(inputChannel = "inputAsync", outputChannel = "outputAsync", async = "true")
|
||||
public ListenableFuture<String> process(String message) {
|
||||
SettableListenableFuture<String> future = new SettableListenableFuture<>();
|
||||
future.set(message);
|
||||
public CompletableFuture<String> process(String message) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
future.complete(message);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -59,7 +59,6 @@ import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
@@ -403,7 +402,7 @@ public class GatewayParserTests {
|
||||
.setCorrelationId(request.getHeaders().getId()).build();
|
||||
Object payload = null;
|
||||
if (request.getPayload().equals("futureSync")) {
|
||||
payload = new AsyncResult<Message<?>>(reply);
|
||||
payload = CompletableFuture.completedFuture(reply);
|
||||
}
|
||||
else if (request.getPayload().equals("flowCompletable")) {
|
||||
payload = CompletableFuture.<String>completedFuture("SYNC_COMPLETABLE");
|
||||
@@ -448,7 +447,7 @@ public class GatewayParserTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
try {
|
||||
Future<?> result = super.submit(task);
|
||||
@@ -462,7 +461,8 @@ public class GatewayParserTests {
|
||||
modifiedMessage = MessageBuilder.fromMessage(message)
|
||||
.setHeader("executor", this.beanName).build();
|
||||
}
|
||||
return new AsyncResult(modifiedMessage);
|
||||
|
||||
return (Future<T>) CompletableFuture.completedFuture(modifiedMessage);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("unexpected exception in testExecutor", e);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -21,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -39,8 +40,6 @@ import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -105,22 +104,15 @@ public class AsyncGatewayTests {
|
||||
proxyFactory.setBeanFactory(mock(BeanFactory.class));
|
||||
proxyFactory.afterPropertiesSet();
|
||||
TestEchoService service = (TestEchoService) proxyFactory.getObject();
|
||||
ListenableFuture<Message<?>> f = service.returnMessageListenable("foo");
|
||||
CompletableFuture<Message<?>> f = service.returnMessageListenable("foo");
|
||||
long start = System.currentTimeMillis();
|
||||
final AtomicReference<Message<?>> result = new AtomicReference<>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
f.addCallback(new ListenableFutureCallback<Message<?>>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(Message<?> msg) {
|
||||
result.set(msg);
|
||||
f.whenComplete((message, throwable) -> {
|
||||
if (throwable == null) {
|
||||
result.set(message);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
}
|
||||
|
||||
});
|
||||
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
@@ -300,7 +292,7 @@ public class AsyncGatewayTests {
|
||||
String header = (String) input.getHeaders().get("method");
|
||||
if (header != null && header.startsWith("returnCustomFuture")) {
|
||||
reply = MessageBuilder.withPayload(new CustomFuture(payload,
|
||||
(Thread) input.getHeaders().get("thread")))
|
||||
(Thread) input.getHeaders().get("thread")))
|
||||
.copyHeaders(input.getHeaders())
|
||||
.build();
|
||||
}
|
||||
@@ -317,7 +309,7 @@ public class AsyncGatewayTests {
|
||||
|
||||
Future<?> returnSomething(String s);
|
||||
|
||||
ListenableFuture<Message<?>> returnMessageListenable(String s);
|
||||
CompletableFuture<Message<?>> returnMessageListenable(String s);
|
||||
|
||||
@Gateway(headers = @GatewayHeader(name = "method", expression = "#gatewayMethod.name"))
|
||||
CustomFuture returnCustomFuture(String s);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -30,11 +30,11 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -81,13 +81,10 @@ import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.messaging.handler.annotation.Payload;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -399,6 +396,7 @@ public class GatewayInterfaceTests {
|
||||
* performed the send() on gatewayThreadChannel.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void testExecs() throws Exception {
|
||||
assertThat(TestUtils.getPropertyValue(execGatewayFB, "asyncExecutor")).isSameAs(exec);
|
||||
assertThat(TestUtils.getPropertyValue(noExecGatewayFB, "asyncExecutor")).isNull();
|
||||
@@ -414,25 +412,23 @@ public class GatewayInterfaceTests {
|
||||
result = this.noExecGateway.test1(Thread.currentThread());
|
||||
assertThat(result.get()).isEqualTo(Thread.currentThread());
|
||||
|
||||
ListenableFuture<Thread> result2 = this.execGateway.test2(Thread.currentThread());
|
||||
CompletableFuture<Thread> result2 = this.execGateway.test2(Thread.currentThread());
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicReference<Thread> thread = new AtomicReference<>();
|
||||
result2.addCallback(new ListenableFutureCallback<>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(Thread result) {
|
||||
thread.set(result);
|
||||
result2.whenComplete((currentThread, throwable) -> {
|
||||
if (throwable == null) {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
}
|
||||
|
||||
});
|
||||
assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
|
||||
assertThat(result2.get().getName()).startsWith("exec-");
|
||||
|
||||
org.springframework.util.concurrent.ListenableFuture<Thread> 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))
|
||||
@@ -615,7 +611,7 @@ public class GatewayInterfaceTests {
|
||||
Object payload;
|
||||
if (Thread.currentThread().equals(message.getPayload())) {
|
||||
// running on calling thread - need to return a Future.
|
||||
payload = new AsyncResult<>(Thread.currentThread());
|
||||
payload = CompletableFuture.completedFuture(Thread.currentThread());
|
||||
}
|
||||
else {
|
||||
payload = Thread.currentThread();
|
||||
@@ -683,7 +679,11 @@ public class GatewayInterfaceTests {
|
||||
Future<Thread> test1(Thread caller);
|
||||
|
||||
@Gateway(requestChannel = "gatewayThreadChannel")
|
||||
ListenableFuture<Thread> test2(Thread caller);
|
||||
CompletableFuture<Thread> test2(Thread caller);
|
||||
|
||||
@Gateway(requestChannel = "gatewayThreadChannel")
|
||||
@SuppressWarnings("deprecation")
|
||||
org.springframework.util.concurrent.ListenableFuture<Thread> test3(Thread caller);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -46,7 +47,6 @@ import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.core.DestinationResolutionException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
@@ -80,19 +80,14 @@ public class AsyncHandlerTests {
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
final SettableListenableFuture<String> future = new SettableListenableFuture<>();
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
AsyncHandlerTests.this.executor.execute(() -> {
|
||||
try {
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
switch (whichTest) {
|
||||
case 0:
|
||||
future.set("reply");
|
||||
break;
|
||||
case 1:
|
||||
future.setException(new RuntimeException("foo"));
|
||||
break;
|
||||
case 2:
|
||||
future.setException(new MessagingException(requestMessage));
|
||||
case 0 -> future.complete("reply");
|
||||
case 1 -> future.completeExceptionally(new RuntimeException("foo"));
|
||||
case 2 -> future.completeExceptionally(new MessagingException(requestMessage));
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.integration.handler;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -43,8 +44,6 @@ import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
/**
|
||||
* See INT-1688 for background.
|
||||
@@ -210,7 +209,7 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
|
||||
this.asyncIn.send(message);
|
||||
Message<?> reply = replyChannel.receive(0);
|
||||
assertThat(reply).isNull();
|
||||
this.asyncService.future.set(this.asyncService.payload.toUpperCase());
|
||||
this.asyncService.future.complete(this.asyncService.payload.toUpperCase());
|
||||
reply = replyChannel.receive(0);
|
||||
assertThat(reply).isNotNull();
|
||||
assertThat(reply.getPayload()).isEqualTo("TEST");
|
||||
@@ -225,7 +224,7 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
|
||||
Message<?> message = MessageBuilder.withPayload("testing").setReplyChannel(replyChannel).build();
|
||||
this.asyncIn.send(message);
|
||||
assertThat(reply.get()).isNull();
|
||||
this.asyncService.future.set(this.asyncService.payload.toUpperCase());
|
||||
this.asyncService.future.complete(this.asyncService.payload.toUpperCase());
|
||||
assertThat(reply.get()).isNotNull();
|
||||
assertThat(reply.get().getPayload()).isEqualTo("TESTING");
|
||||
}
|
||||
@@ -235,7 +234,7 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
|
||||
QueueChannel errorChannel = new QueueChannel();
|
||||
Message<?> message = MessageBuilder.withPayload("test").setErrorChannel(errorChannel).build();
|
||||
this.asyncIn.send(message);
|
||||
this.asyncService.future.setException(new RuntimeException("intended"));
|
||||
this.asyncService.future.completeExceptionally(new RuntimeException("intended"));
|
||||
Message<?> error = errorChannel.receive(0);
|
||||
assertThat(error).isNotNull();
|
||||
assertThat(error).isInstanceOf(ErrorMessage.class);
|
||||
@@ -249,7 +248,7 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
|
||||
public void testAsyncErrorNoHeader() {
|
||||
Message<?> message = MessageBuilder.withPayload("test").build();
|
||||
this.asyncIn.send(message);
|
||||
this.asyncService.future.setException(new RuntimeException("intended"));
|
||||
this.asyncService.future.completeExceptionally(new RuntimeException("intended"));
|
||||
Message<?> error = this.errorChannel.receive(0);
|
||||
assertThat(error).isNotNull();
|
||||
assertThat(error).isInstanceOf(ErrorMessage.class);
|
||||
@@ -326,13 +325,13 @@ public class ServiceActivatorDefaultFrameworkMethodTests {
|
||||
|
||||
private static class AsyncService {
|
||||
|
||||
private volatile SettableListenableFuture<String> future;
|
||||
private volatile CompletableFuture<String> future;
|
||||
|
||||
private volatile String payload;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public ListenableFuture<String> process(String payload) {
|
||||
this.future = new SettableListenableFuture<>();
|
||||
public CompletableFuture<String> process(String payload) {
|
||||
this.future = new CompletableFuture<>();
|
||||
this.payload = payload;
|
||||
return this.future;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user