Add generic arg to the GatewayProxyFactoryBean (#3925)

* Add generic arg to the `GatewayProxyFactoryBean`

Related to https://github.com/spring-projects/spring-integration/issues/3923

When gateway proxy is declared manually, a `GatewayProxyFactoryBean` is used as a `@Bean`.
In this case the info about target interface is not available on a `BeanDefinition`,
unlike with a programmatic registration via `MessagingGatewayRegistrar`.

* Expose `<T>` on a `GatewayProxyFactoryBean` to make end-user to specify the type
this gateway is going to be based on.
This allows Spring container to determine the type of the `FactoryBean` bean definition
properly
* Migrate a programmatic bean definition registration from the
`FactoryBean.OBJECT_TYPE_ATTRIBUTE` to the `targetType` property
of the `BeanDefinition` based on a `ResolvableType.forClassWithGenerics()`
to simulate generic arg for the application context
* Remove `ComponentsRegistration` from the `GatewayProxySpec` since it us out of use
* Fix affected tests for newly added generic arg on the `GatewayProxyFactoryBean`

* Fix another typo in gateway.adoc

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2022-10-25 12:09:33 -04:00
committed by GitHub
parent bcbf37c405
commit e52e352e0c
21 changed files with 176 additions and 157 deletions

View File

@@ -24,11 +24,9 @@ import java.util.Map.Entry;
import java.util.Set;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -37,6 +35,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Primary;
import org.springframework.core.ResolvableType;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.AnnotationConstants;
@@ -112,8 +111,8 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar
Class<?> serviceInterface = getServiceInterface((String) gatewayAttributes.get("serviceInterface"), beanFactory);
BeanDefinitionBuilder gatewayProxyBuilder =
BeanDefinitionBuilder.genericBeanDefinition(GatewayProxyFactoryBean.class,
() -> new GatewayProxyFactoryBean(serviceInterface));
BeanDefinitionBuilder.rootBeanDefinition(GatewayProxyFactoryBean.class,
() -> new GatewayProxyFactoryBean<>(serviceInterface));
if (hasDefaultHeaders || hasDefaultPayloadExpression) {
BeanDefinitionBuilder methodMetadataBuilder =
@@ -190,8 +189,9 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar
gatewayProxyBuilder.addConstructorArgValue(serviceInterface);
gatewayProxyBuilder.setPrimary(gatewayAttributes.containsKey(PRIMARY_ATTR));
AbstractBeanDefinition beanDefinition = gatewayProxyBuilder.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, serviceInterface);
RootBeanDefinition beanDefinition = (RootBeanDefinition) gatewayProxyBuilder.getBeanDefinition();
beanDefinition.setTargetType(
ResolvableType.forClassWithGenerics(GatewayProxyFactoryBean.class, serviceInterface));
return new BeanDefinitionHolder(beanDefinition, id);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-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.
@@ -16,7 +16,6 @@
package org.springframework.integration.dsl;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -42,15 +41,16 @@ import org.springframework.messaging.MessageChannel;
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.2
*/
public class GatewayProxySpec implements ComponentsRegistration {
public class GatewayProxySpec {
protected static final SpelExpressionParser PARSER = new SpelExpressionParser(); // NOSONAR - final
protected static final SpelExpressionParser PARSER = new SpelExpressionParser(); // NOSONAR - final
protected final MessageChannel gatewayRequestChannel = new DirectChannel(); // NOSONAR - final
protected final GatewayProxyFactoryBean gatewayProxyFactoryBean; // NOSONAR - final
protected final GatewayProxyFactoryBean<?> gatewayProxyFactoryBean; // NOSONAR - final
protected final GatewayMethodMetadata gatewayMethodMetadata = new GatewayMethodMetadata(); // NOSONAR - final
@@ -59,7 +59,7 @@ public class GatewayProxySpec implements ComponentsRegistration {
private boolean populateGatewayMethodMetadata;
protected GatewayProxySpec(Class<?> serviceInterface) {
this.gatewayProxyFactoryBean = new AnnotationGatewayProxyFactoryBean(serviceInterface);
this.gatewayProxyFactoryBean = new AnnotationGatewayProxyFactoryBean<>(serviceInterface);
this.gatewayProxyFactoryBean.setDefaultRequestChannel(this.gatewayRequestChannel);
}
@@ -145,7 +145,7 @@ public class GatewayProxySpec implements ComponentsRegistration {
/**
* Allows to specify how long this gateway will wait for the reply {@code Message}
* before returning. By default it will wait indefinitely. {@code null} is returned if
* before returning. By default, it will wait indefinitely. {@code null} is returned if
* the gateway times out. Value is specified in milliseconds.
* @param replyTimeout the timeout for replies in milliseconds.
* @return current {@link GatewayProxySpec}.
@@ -280,7 +280,7 @@ public class GatewayProxySpec implements ComponentsRegistration {
return this.gatewayRequestChannel;
}
GatewayProxyFactoryBean getGatewayProxyFactoryBean() {
GatewayProxyFactoryBean<?> getGatewayProxyFactoryBean() {
if (this.populateGatewayMethodMetadata) {
this.gatewayMethodMetadata.setHeaderExpressions(this.headerExpressions);
this.gatewayProxyFactoryBean.setGlobalMethodMetadata(this.gatewayMethodMetadata);
@@ -288,10 +288,4 @@ public class GatewayProxySpec implements ComponentsRegistration {
return this.gatewayProxyFactoryBean;
}
@Override
public Map<Object, String> getComponentsToRegister() {
return Collections.singletonMap(this.gatewayProxyFactoryBean, this.gatewayProxyFactoryBean.getBeanName()
+ ".gateway");
}
}

View File

@@ -252,8 +252,7 @@ public class IntegrationFlowBeanPostProcessor
registerComponent(component, subFlowBeanName, flowBeanName);
targetIntegrationComponents.put(component, subFlowBeanName);
}
else if (component instanceof AnnotationGatewayProxyFactoryBean) {
AnnotationGatewayProxyFactoryBean gateway = (AnnotationGatewayProxyFactoryBean) component;
else if (component instanceof AnnotationGatewayProxyFactoryBean<?> gateway) {
String gatewayId = entry.getValue();
if (gatewayId == null) {
@@ -264,10 +263,8 @@ public class IntegrationFlowBeanPostProcessor
}
registerComponent(gateway, gatewayId, flowBeanName,
beanDefinition -> {
((AbstractBeanDefinition) beanDefinition)
.setSource(new DescriptiveResource("" + gateway.getObjectType()));
});
beanDefinition -> ((AbstractBeanDefinition) beanDefinition)
.setSource(new DescriptiveResource("" + gateway.getObjectType())));
targetIntegrationComponents.put(component, gatewayId);
}
@@ -431,7 +428,7 @@ public class IntegrationFlowBeanPostProcessor
BeanDefinitionCustomizer... customizers) {
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) component.getClass(), () -> component)
BeanDefinitionBuilder.rootBeanDefinition((Class<Object>) component.getClass(), () -> component)
.applyCustomizers(customizers)
.getRawBeanDefinition();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2021 the original author or authors.
* Copyright 2017-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.
@@ -39,18 +39,20 @@ import org.springframework.util.StringUtils;
/**
* A {@link GatewayProxyFactoryBean} extension for Java configuration.
* The service interface may be marked with the {@link MessagingGateway} annotation.
* Otherwise the default state is applied.
* Otherwise, the default state is applied.
*
* @param <T> the target gateway interface to build a proxy against.
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.0
*/
public class AnnotationGatewayProxyFactoryBean extends GatewayProxyFactoryBean {
public class AnnotationGatewayProxyFactoryBean<T> extends GatewayProxyFactoryBean<T> {
private final AnnotationAttributes gatewayAttributes;
public AnnotationGatewayProxyFactoryBean(Class<?> serviceInterface) {
public AnnotationGatewayProxyFactoryBean(Class<T> serviceInterface) {
super(serviceInterface);
AnnotationAttributes annotationAttributes =

View File

@@ -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.
@@ -33,14 +33,14 @@ import org.springframework.messaging.MessageChannel;
*/
public class GatewayMessageHandler extends AbstractReplyProducingMessageHandler implements ManageableLifecycle {
private final GatewayProxyFactoryBean gatewayProxyFactoryBean;
private final GatewayProxyFactoryBean<?> gatewayProxyFactoryBean;
private RequestReplyExchanger exchanger;
private volatile RequestReplyExchanger exchanger;
private volatile boolean running;
public GatewayMessageHandler() {
this.gatewayProxyFactoryBean = new GatewayProxyFactoryBean();
this.gatewayProxyFactoryBean = new GatewayProxyFactoryBean<>();
}
public void setRequestChannel(MessageChannel requestChannel) {

View File

@@ -99,20 +99,22 @@ import reactor.core.publisher.Mono;
* to
* perform type conversions when necessary (thanks to Jon Schneider's contribution and suggestion in INT-1230).
*
* @param <T> the target gateway interface to build a proxy against.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*/
public class GatewayProxyFactoryBean extends AbstractEndpoint
implements TrackableComponent, FactoryBean<Object>, MethodInterceptor, BeanClassLoaderAware,
public class GatewayProxyFactoryBean<T> extends AbstractEndpoint
implements TrackableComponent, FactoryBean<T>, MethodInterceptor, BeanClassLoaderAware,
IntegrationManagement {
private final Object initializationMonitor = new Object();
private final Map<Method, MethodInvocationGateway> gatewayMap = new HashMap<>();
private final Class<?> serviceInterface;
private final Class<T> serviceInterface;
private final Set<Method> havePayloadExpressions = new HashSet<>();
@@ -140,7 +142,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private Object serviceProxy;
private T serviceProxy;
private AsyncTaskExecutor asyncExecutor = new SimpleAsyncTaskExecutor();
@@ -165,11 +167,12 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
* If none is set, it will fall back to the default service interface type,
* {@link RequestReplyExchanger}, upon initialization.
*/
@SuppressWarnings("unchecked")
public GatewayProxyFactoryBean() {
this.serviceInterface = RequestReplyExchanger.class;
this((Class<T>) RequestReplyExchanger.class);
}
public GatewayProxyFactoryBean(Class<?> serviceInterface) {
public GatewayProxyFactoryBean(Class<T> serviceInterface) {
Assert.notNull(serviceInterface, "'serviceInterface' must not be null");
Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface");
this.serviceInterface = serviceInterface;
@@ -449,6 +452,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
}
@Override
@SuppressWarnings("unchecked")
protected void onInit() {
synchronized (this.initializationMonitor) {
if (this.initialized) {
@@ -464,7 +468,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
ProxyFactory gatewayProxyFactory =
new ProxyFactory(this.serviceInterface, this);
gatewayProxyFactory.addAdvice(new DefaultMethodInvokingMethodInterceptor());
this.serviceProxy = gatewayProxyFactory.getProxy(this.beanClassLoader);
this.serviceProxy = (T) gatewayProxyFactory.getProxy(this.beanClassLoader);
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory);
this.initialized = true;
}
@@ -489,7 +493,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
}
@Override
public Object getObject() {
public T getObject() {
if (this.serviceProxy == null) {
this.onInit();
Assert.notNull(this.serviceProxy, "failed to initialize proxy");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 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.
@@ -236,9 +236,10 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
.peek(nodes::add)
.forEach(gatewayNode -> producerLink(links, channelNodes, gatewayNode));
Map<String, GatewayProxyFactoryBean> gpfbs = getBeansOfType(GatewayProxyFactoryBean.class);
@SuppressWarnings({ "rawtypes", "unchecked"})
Map<String, GatewayProxyFactoryBean<?>> gpfbs = (Map) getBeansOfType(GatewayProxyFactoryBean.class);
for (Entry<String, GatewayProxyFactoryBean> entry : gpfbs.entrySet()) {
for (Entry<String, GatewayProxyFactoryBean<?>> entry : gpfbs.entrySet()) {
entry.getValue()
.getGateways()
.entrySet()

View File

@@ -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.
@@ -392,8 +392,8 @@ public class ChainParserTests {
.isTrue();
assertThat(this.beanFactory.containsBean("subComponentsIdSupport1$child.gatewayWithinChain.handler")).isTrue();
//INT-3117
GatewayProxyFactoryBean gatewayProxyFactoryBean = this.beanFactory.getBean("&subComponentsIdSupport1$child" +
".gatewayWithinChain.handler",
GatewayProxyFactoryBean<?> gatewayProxyFactoryBean =
this.beanFactory.getBean("&subComponentsIdSupport1$child.gatewayWithinChain.handler",
GatewayProxyFactoryBean.class);
assertThat(TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestChannelName"))
.isEqualTo("strings");

View File

@@ -36,11 +36,12 @@ import org.mockito.ArgumentMatchers;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.core.log.LogAccessor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.expression.Expression;
@@ -111,7 +112,7 @@ public class GatewayParserTests {
assertThat(result.getPayload()).isEqualTo("fiz");
assertThat(result.getHeaders().get("foo")).isEqualTo("bar");
assertThat(result.getHeaders().get("baz")).isEqualTo("qux");
GatewayProxyFactoryBean fb = context.getBean("&methodOverride", GatewayProxyFactoryBean.class);
GatewayProxyFactoryBean<?> fb = context.getBean("&methodOverride", GatewayProxyFactoryBean.class);
assertThat(TestUtils.getPropertyValue(fb, "defaultRequestTimeout", Expression.class).getValue())
.isEqualTo(1000L);
assertThat(TestUtils.getPropertyValue(fb, "defaultReplyTimeout", Expression.class).getValue()).isEqualTo(2000L);
@@ -198,17 +199,17 @@ public class GatewayParserTests {
@Test
public void testFactoryBeanObjectTypeWithServiceInterface() {
ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory();
Object attribute =
beanFactory.getMergedBeanDefinition("&oneWay").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
assertThat(attribute).isEqualTo(TestService.class);
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition("&oneWay");
ResolvableType resolvableType = beanDefinition.getResolvableType();
assertThat(resolvableType.getGeneric(0).getRawClass()).isEqualTo(TestService.class);
}
@Test
public void testFactoryBeanObjectTypeWithNoServiceInterface() {
ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext) context).getBeanFactory();
Object attribute =
beanFactory.getMergedBeanDefinition("&defaultConfig").getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
assertThat(attribute).isEqualTo(RequestReplyExchanger.class);
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition("&defaultConfig");
ResolvableType resolvableType = beanDefinition.getResolvableType();
assertThat(resolvableType.getGeneric(0).getRawClass()).isEqualTo(RequestReplyExchanger.class);
}
@Test

View File

@@ -34,7 +34,7 @@ import java.util.function.Supplier;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.After;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
@@ -527,7 +527,7 @@ public class IntegrationFlowTests {
public void testStandardIntegrationFlowLifecycle() {
this.controlBusFlow.stop();
GatewayProxyFactoryBean controlBusGateway =
GatewayProxyFactoryBean<?> controlBusGateway =
this.beanFactory.getBean("&controlBusGateway", GatewayProxyFactoryBean.class);
assertThat(controlBusGateway.isRunning()).isFalse();
Lifecycle controlBus = this.beanFactory.getBean("controlBus", Lifecycle.class);
@@ -540,7 +540,7 @@ public class IntegrationFlowTests {
}
@After
@AfterEach
public void cleanUpList() {
outputStringList.clear();
}

View File

@@ -114,7 +114,7 @@ public class GatewayDslTests {
@Autowired
@Qualifier("&functionGateway.gateway")
private GatewayProxyFactoryBean functionGatewayFactoryBean;
private GatewayProxyFactoryBean<?> functionGatewayFactoryBean;
@Test
void testHeadersFromFunctionGateway() {
@@ -154,7 +154,7 @@ public class GatewayDslTests {
@Autowired
@Qualifier("&routingGateway")
private GatewayProxyFactoryBean routingGatewayProxy;
private GatewayProxyFactoryBean<?> routingGatewayProxy;
@Test
void testRoutingGateway() {

View File

@@ -63,12 +63,12 @@ public class AsyncGatewayTests {
public void futureWithMessageReturned() throws Exception {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<Message<?>> f = service.returnMessage("foo");
Object result = f.get(10000, TimeUnit.MILLISECONDS);
assertThat(result).isNotNull();
@@ -86,12 +86,12 @@ public class AsyncGatewayTests {
}
};
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(channel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<Message<?>> f = service.returnMessage("foo");
assertThatExceptionOfType(ExecutionException.class)
@@ -104,12 +104,12 @@ public class AsyncGatewayTests {
QueueChannel requestChannel = new QueueChannel();
addThreadEnricher(requestChannel);
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
CompletableFuture<Message<?>> f = service.returnMessageListenable("foo");
long start = System.currentTimeMillis();
final AtomicReference<Message<?>> result = new AtomicReference<>();
@@ -133,12 +133,12 @@ public class AsyncGatewayTests {
QueueChannel requestChannel = new QueueChannel();
addThreadEnricher(requestChannel);
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
CustomFuture f = service.returnCustomFuture("foo");
String result = f.get(10000, TimeUnit.MILLISECONDS);
assertThat(result).isEqualTo("foobar");
@@ -150,7 +150,7 @@ public class AsyncGatewayTests {
QueueChannel requestChannel = new QueueChannel();
addThreadEnricher(requestChannel);
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
@@ -158,7 +158,7 @@ public class AsyncGatewayTests {
proxyFactory.setAsyncExecutor(null); // Not async - user flow returns Future<?>
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
CustomFuture f = (CustomFuture) service.returnCustomFutureWithTypeFuture("foo");
String result = f.get(10000, TimeUnit.MILLISECONDS);
assertThat(result).isEqualTo("foobar");
@@ -182,12 +182,12 @@ public class AsyncGatewayTests {
public void futureWithPayloadReturned() throws Exception {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<String> f = service.returnString("foo");
Object result = f.get(10000, TimeUnit.MILLISECONDS);
assertThat(result).isNotNull();
@@ -198,12 +198,12 @@ public class AsyncGatewayTests {
public void futureWithWildcardReturned() throws Exception {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<?> f = service.returnSomething("foo");
Object result = f.get(10000, TimeUnit.MILLISECONDS);
assertThat(result instanceof String).isTrue();
@@ -212,12 +212,12 @@ public class AsyncGatewayTests {
@Test
public void futureVoid() throws Exception {
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(new NullChannel());
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<Void> f = service.asyncSendAndForget("test1");
Object result = f.get(10, TimeUnit.SECONDS);
assertThat(result).isNull();
@@ -252,13 +252,13 @@ public class AsyncGatewayTests {
ReflectionUtils.rethrowRuntimeException(ex);
}
}).start();
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setAsyncExecutor(null);
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Future<Void> f = service.sendAndReceiveFutureVoid("test");
readyForReplyLatch.countDown();
Object result = f.get(10, TimeUnit.SECONDS);
@@ -269,12 +269,12 @@ public class AsyncGatewayTests {
public void monoWithMessageReturned() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Mono<Message<?>> mono = service.returnMessagePromise("foo");
Object result = mono.block(Duration.ofSeconds(10));
assertThat(((Message<?>) result).getPayload()).isEqualTo("foobar");
@@ -284,12 +284,12 @@ public class AsyncGatewayTests {
public void monoWithPayloadReturned() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Mono<String> mono = service.returnStringPromise("foo");
Object result = mono.block(Duration.ofSeconds(10));
assertThat(result).isEqualTo("foobar");
@@ -299,12 +299,12 @@ public class AsyncGatewayTests {
public void monoWithWildcardReturned() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Mono<?> mono = service.returnSomethingPromise("foo");
Object result = mono.block(Duration.ofSeconds(10));
assertThat(result).isNotNull();
@@ -315,12 +315,12 @@ public class AsyncGatewayTests {
public void monoWithConsumer() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Mono<String> mono = service.returnStringPromise("foo");
StepVerifier.create(mono)
@@ -330,12 +330,12 @@ public class AsyncGatewayTests {
@Test
public void monoVoid() throws InterruptedException {
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> proxyFactory = new GatewayProxyFactoryBean<>(TestEchoService.class);
proxyFactory.setDefaultRequestChannel(new NullChannel());
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestEchoService service = (TestEchoService) proxyFactory.getObject();
TestEchoService service = proxyFactory.getObject();
Mono<Void> mono = service.monoVoid("test1");
CountDownLatch emptyMonoLatch = new CountDownLatch(1);

View File

@@ -41,13 +41,16 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Primary;
@@ -55,6 +58,7 @@ import org.springframework.context.annotation.Profile;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.expression.Expression;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.AnnotationConstants;
@@ -103,7 +107,7 @@ public class GatewayInterfaceTests {
private static final String IGNORE_HEADER = "ignoreHeader";
@Autowired
private BeanFactory beanFactory;
private ListableBeanFactory beanFactory;
@Autowired
private Int2634Gateway int2634Gateway;
@@ -116,11 +120,11 @@ public class GatewayInterfaceTests {
@Autowired
@Qualifier("&gatewayInterfaceTests$ExecGateway")
private GatewayProxyFactoryBean execGatewayFB;
private GatewayProxyFactoryBean<?> execGatewayFB;
@Autowired
@Qualifier("&gatewayInterfaceTests$NoExecGateway")
private GatewayProxyFactoryBean noExecGatewayFB;
private GatewayProxyFactoryBean<?> noExecGatewayFB;
@Autowired
private SimpleAsyncTaskExecutor exec;
@@ -136,7 +140,7 @@ public class GatewayInterfaceTests {
@Autowired
@Qualifier("&annotationGatewayProxyFactoryBean")
private GatewayProxyFactoryBean annotationGatewayProxyFactoryBean;
private GatewayProxyFactoryBean<?> annotationGatewayProxyFactoryBean;
@Autowired
private MessageChannel gatewayChannel;
@@ -319,7 +323,7 @@ public class GatewayInterfaceTests {
channel.subscribe(handler);
Bar bar = ac.getBean(Bar.class);
assertThat(ac.getBean(Bar.class)).isSameAs(bar);
GatewayProxyFactoryBean fb = new GatewayProxyFactoryBean(Bar.class);
GatewayProxyFactoryBean<Bar> fb = new GatewayProxyFactoryBean<>(Bar.class);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerSingleton("requestChannelBar", channel);
bf.registerSingleton("requestChannelBaz", channel);
@@ -346,7 +350,7 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceAsNotAnInterface() {
assertThatIllegalArgumentException().isThrownBy(() -> new GatewayProxyFactoryBean(NotAnInterface.class));
assertThatIllegalArgumentException().isThrownBy(() -> new GatewayProxyFactoryBean<>(NotAnInterface.class));
}
@Test
@@ -399,7 +403,7 @@ public class GatewayInterfaceTests {
/*
* Tests use current thread in payload and reply has the thread that actually
* performed the send() on gatewayThreadChannel.
* performed the 'send()' on gatewayThreadChannel.
*/
@Test
@SuppressWarnings("deprecation")
@@ -674,12 +678,13 @@ public class GatewayInterfaceTests {
@Bean
public GatewayProxyFactoryBean annotationGatewayProxyFactoryBean() {
return new AnnotationGatewayProxyFactoryBean(GatewayByAnnotationGPFB.class);
public GatewayProxyFactoryBean<GatewayByAnnotationGPFB> annotationGatewayProxyFactoryBean() {
return new AnnotationGatewayProxyFactoryBean<>(GatewayByAnnotationGPFB.class);
}
@Conditional(GatewayByAnnotationGPFBCondition.class)
@Bean
PrimaryGateway notPrimaryGatewayInstance() {
PrimaryGateway notPrimaryGatewayInstance(GatewayByAnnotationGPFB annotationGPFB) {
return payload -> { };
}
@@ -792,4 +797,13 @@ public class GatewayInterfaceTests {
}
public static class GatewayByAnnotationGPFBCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getBeanFactory().getBeanNamesForType(GatewayByAnnotationGPFB.class).length > 0;
}
}
}

View File

@@ -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.
@@ -77,12 +77,12 @@ public class GatewayProxyFactoryBeanTests {
public void testRequestReplyWithAnonymousChannel() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
String result = service.requestReply("foo");
assertThat(result).isEqualTo("foobar");
}
@@ -104,7 +104,7 @@ public class GatewayProxyFactoryBeanTests {
};
stringToByteConverter = spy(stringToByteConverter);
cs.addConverter(stringToByteConverter);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerSingleton(IntegrationUtils.INTEGRATION_CONVERSION_SERVICE_BEAN_NAME, cs);
@@ -112,7 +112,7 @@ public class GatewayProxyFactoryBeanTests {
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
byte[] result = service.requestReplyInBytes("foo");
assertThat(result.length).isEqualTo(6);
Mockito.verify(stringToByteConverter, Mockito.times(1)).convert(Mockito.any(String.class));
@@ -121,12 +121,12 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testOneWay() {
final QueueChannel requestChannel = new QueueChannel();
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
service.oneWay("test");
Message<?> message = requestChannel.receive(1000);
assertThat(message).isNotNull();
@@ -145,12 +145,12 @@ public class GatewayProxyFactoryBeanTests {
handler.setBeanFactory(beanFactory);
handler.afterPropertiesSet();
requestChannel.subscribe(handler);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(beanFactory);
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
service.oneWay("test");
Message<?> message = nullChannel.receive(1000);
assertThat(message)
@@ -163,13 +163,13 @@ public class GatewayProxyFactoryBeanTests {
public void testSolicitResponse() {
QueueChannel replyChannel = new QueueChannel();
replyChannel.send(new GenericMessage<>("foo"));
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(new DirectChannel());
proxyFactory.setDefaultReplyChannel(replyChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
String result = service.solicitResponse();
assertThat(result).isNotNull();
assertThat(result).isEqualTo("foo");
@@ -179,12 +179,12 @@ public class GatewayProxyFactoryBeanTests {
public void testReceiveMessage() {
QueueChannel replyChannel = new QueueChannel();
replyChannel.send(new GenericMessage<>("foo"));
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultReplyChannel(replyChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
Message<String> message = service.getMessage();
assertThat(message).isNotNull();
assertThat(message.getPayload()).isEqualTo("foo");
@@ -200,13 +200,13 @@ public class GatewayProxyFactoryBeanTests {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
FluxMessageChannel replyChannel = new FluxMessageChannel();
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setDefaultReplyChannel(replyChannel);
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
String result = service.requestReply("test");
assertThat(result).isEqualTo("testbar");
@@ -220,12 +220,12 @@ public class GatewayProxyFactoryBeanTests {
GenericMessage<String> reply = new GenericMessage<>(input.getPayload() + "456");
((MessageChannel) input.getHeaders().getReplyChannel()).send(reply);
}).start();
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
Integer result = service.requestReplyWithIntegers(123);
assertThat(result).isEqualTo(123456);
}
@@ -291,12 +291,12 @@ public class GatewayProxyFactoryBeanTests {
public void testMessageAsMethodArgument() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
String result = service.requestReplyWithMessageParameter(new GenericMessage<>("foo"));
assertThat(result).isEqualTo("foobar");
}
@@ -305,12 +305,12 @@ public class GatewayProxyFactoryBeanTests {
public void testNoArgMethodWithPayloadAnnotation() {
QueueChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
String result = service.requestReplyWithPayloadAnnotation();
assertThat(result).isEqualTo("requestReplyWithPayloadAnnotation0bar");
@@ -329,12 +329,12 @@ public class GatewayProxyFactoryBeanTests {
GenericMessage<String> reply = new GenericMessage<>(input.getPayload() + "bar");
((MessageChannel) input.getHeaders().getReplyChannel()).send(reply);
}).start();
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(requestChannel);
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
TestService service = proxyFactory.getObject();
Message<?> result = service.requestReplyWithMessageReturnValue("foo");
assertThat(result.getPayload()).isEqualTo("foobar");
}
@@ -342,12 +342,12 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testServiceMustBeInterface() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new GatewayProxyFactoryBean(String.class));
.isThrownBy(() -> new GatewayProxyFactoryBean<>(String.class));
}
@Test
public void testProxiedToStringMethod() {
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestService.class);
GatewayProxyFactoryBean<TestService> proxyFactory = new GatewayProxyFactoryBean<>(TestService.class);
proxyFactory.setDefaultRequestChannel(new DirectChannel());
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
@@ -359,7 +359,8 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testCheckedExceptionRethrownAsIs() {
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean(TestExceptionThrowingInterface.class);
GatewayProxyFactoryBean<TestExceptionThrowingInterface> proxyFactory =
new GatewayProxyFactoryBean<>(TestExceptionThrowingInterface.class);
DirectChannel channel = new DirectChannel();
EventDrivenConsumer consumer = new EventDrivenConsumer(channel, new MessageHandler() {
@@ -375,7 +376,7 @@ public class GatewayProxyFactoryBeanTests {
proxyFactory.setBeanName("testGateway");
proxyFactory.setBeanFactory(mock(BeanFactory.class));
proxyFactory.afterPropertiesSet();
TestExceptionThrowingInterface proxy = (TestExceptionThrowingInterface) proxyFactory.getObject();
TestExceptionThrowingInterface proxy = proxyFactory.getObject();
assertThatExceptionOfType(TestException.class)
.isThrownBy(() -> proxy.throwCheckedException("test"));
}
@@ -391,7 +392,7 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testProgrammaticWiring() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(TestEchoService.class);
GatewayProxyFactoryBean<TestEchoService> gpfb = new GatewayProxyFactoryBean<>(TestEchoService.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
QueueChannel drc = new QueueChannel();
gpfb.setDefaultRequestChannel(drc);
@@ -400,7 +401,7 @@ public class GatewayProxyFactoryBeanTests {
meta.setHeaderExpressions(Collections.singletonMap("foo", new LiteralExpression("bar")));
gpfb.setGlobalMethodMetadata(meta);
gpfb.afterPropertiesSet();
((TestEchoService) gpfb.getObject()).echo("foo");
gpfb.getObject().echo("foo");
Message<?> message = drc.receive(0);
assertThat(message).isNotNull();
String bar = (String) message.getHeaders().get("foo");
@@ -410,7 +411,7 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testIdHeaderOverrideHeaderExpression() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean();
GatewayProxyFactoryBean<?> gpfb = new GatewayProxyFactoryBean<>();
gpfb.setBeanFactory(mock(BeanFactory.class));
GatewayMethodMetadata meta = new GatewayMethodMetadata();
@@ -424,7 +425,8 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testIdHeaderOverrideGatewayHeaderAnnotation() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(HeadersOverwriteService.class);
GatewayProxyFactoryBean<HeadersOverwriteService> gpfb =
new GatewayProxyFactoryBean<>(HeadersOverwriteService.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
assertThatExceptionOfType(BeanInitializationException.class)
@@ -434,7 +436,7 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testTimeStampHeaderOverrideParamHeaderAnnotation() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(HeadersParamService.class);
GatewayProxyFactoryBean<HeadersParamService> gpfb = new GatewayProxyFactoryBean<>(HeadersParamService.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
assertThatExceptionOfType(BeanInitializationException.class)
@@ -487,7 +489,7 @@ public class GatewayProxyFactoryBeanTests {
@Test
public void testOverriddenMethod() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(InheritChild.class);
GatewayProxyFactoryBean<InheritChild> gpfb = new GatewayProxyFactoryBean<>(InheritChild.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
gpfb.afterPropertiesSet();
Map<Method, MessagingGatewaySupport> gateways = gpfb.getGateways();

View File

@@ -51,7 +51,7 @@ public class GatewayProxyMessageMappingTests {
@BeforeEach
public void initializeGateway() {
GatewayProxyFactoryBean factoryBean = new GatewayProxyFactoryBean(TestGateway.class);
GatewayProxyFactoryBean<TestGateway> factoryBean = new GatewayProxyFactoryBean<>(TestGateway.class);
factoryBean.setDefaultRequestChannel(channel);
factoryBean.setBeanName("testGateway");
GenericApplicationContext context = new GenericApplicationContext();
@@ -60,7 +60,7 @@ public class GatewayProxyMessageMappingTests {
context.refresh();
factoryBean.setBeanFactory(context);
factoryBean.afterPropertiesSet();
this.gateway = (TestGateway) factoryBean.getObject();
this.gateway = factoryBean.getObject();
}
@Test

View File

@@ -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.
@@ -22,27 +22,26 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.2
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringJUnitConfig
public class GatewayXmlAndAnnotationTests {
@Autowired
GatewayProxyFactoryBean gatewayProxyFactoryBean;
GatewayProxyFactoryBean<?> gatewayProxyFactoryBean;
@Test
public void test() {
@@ -78,6 +77,7 @@ public class GatewayXmlAndAnnotationTests {
}
public interface AGateway {
@Gateway
String annotationShouldntOverrideDefault(String foo);
@@ -88,5 +88,7 @@ public class GatewayXmlAndAnnotationTests {
String annotationShouldOverrideDefaultToInfinity(String foo);
String explicitTimeoutShouldOverrideDefault(String foo);
}
}

View File

@@ -215,15 +215,15 @@ public class AsyncHandlerTests {
}
@Test
public void testGateway() throws Exception {
public void testGateway() {
this.whichTest = 0;
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(Foo.class);
GatewayProxyFactoryBean<Foo> gpfb = new GatewayProxyFactoryBean<>(Foo.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
DirectChannel input = new DirectChannel();
gpfb.setDefaultRequestChannel(input);
gpfb.setDefaultReplyTimeout(10000L);
gpfb.afterPropertiesSet();
Foo foo = (Foo) gpfb.getObject();
Foo foo = gpfb.getObject();
this.handler.setOutputChannel(null);
EventDrivenConsumer consumer = new EventDrivenConsumer(input, this.handler);
consumer.afterPropertiesSet();
@@ -234,15 +234,15 @@ public class AsyncHandlerTests {
}
@Test
public void testGatewayWithException() throws Exception {
public void testGatewayWithException() {
this.whichTest = 0;
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(Foo.class);
GatewayProxyFactoryBean<Foo> gpfb = new GatewayProxyFactoryBean<>(Foo.class);
gpfb.setBeanFactory(mock(BeanFactory.class));
DirectChannel input = new DirectChannel();
gpfb.setDefaultRequestChannel(input);
gpfb.setDefaultReplyTimeout(10000L);
gpfb.afterPropertiesSet();
Foo foo = (Foo) gpfb.getObject();
Foo foo = gpfb.getObject();
this.handler.setOutputChannel(null);
EventDrivenConsumer consumer = new EventDrivenConsumer(input, this.handler);
consumer.afterPropertiesSet();

View File

@@ -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.
@@ -623,7 +623,7 @@ public class MethodInvokingMessageProcessorTests {
@Test
public void gatewayTest() throws Exception {
GatewayProxyFactoryBean gwFactoryBean = new GatewayProxyFactoryBean();
GatewayProxyFactoryBean<?> gwFactoryBean = new GatewayProxyFactoryBean<>();
gwFactoryBean.setBeanFactory(mock(BeanFactory.class));
gwFactoryBean.afterPropertiesSet();
Object target = gwFactoryBean.getObject();

View File

@@ -345,8 +345,8 @@ public class MicrometerMetricsTests {
}
@Bean
public GatewayProxyFactoryBean gates() {
GatewayProxyFactoryBean gpfb = new GatewayProxyFactoryBean(Gate.class);
public GatewayProxyFactoryBean<Gate> gates() {
GatewayProxyFactoryBean<Gate> gpfb = new GatewayProxyFactoryBean<>(Gate.class);
gpfb.setDefaultRequestChannelName("nullChannel");
return gpfb;
}

View File

@@ -21,6 +21,8 @@ import assertk.assertions.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.ListableBeanFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
@@ -130,7 +132,7 @@ class FunctionsTests {
@Autowired
@Qualifier("&monoFunctionGateway.gateway")
private lateinit var monoFunctionGateway: GatewayProxyFactoryBean
private lateinit var monoFunctionGateway: GatewayProxyFactoryBean<*>
@Test
fun `verify Mono gateway`() {

View File

@@ -312,7 +312,7 @@ public interface TestGateway {
IMPORTANT: Similarly to the XML version, when Spring Integration discovers these annotations during a component scan, it creates the `proxy` implementation with its messaging infrastructure.
To perform this scan and register the `BeanDefinition` in the application context, add the `@IntegrationComponentScan` annotation to a `@Configuration` class.
The standard `@ComponentScan` infrastructure does not deal with interfaces.
Consequently, we introduced the custom `@IntegrationComponentScan` logic to fine the `@MessagingGateway` annotation on the interfaces and register `GatewayProxyFactoryBean` instances for them.
Consequently, we introduced the custom `@IntegrationComponentScan` logic to find the `@MessagingGateway` annotation on the interfaces and register `GatewayProxyFactoryBean` instances for them.
See also <<./configuration.adoc#annotations,Annotation Support>>.
Along with the `@MessagingGateway` annotation you can mark a service interface with the `@Profile` annotation to avoid the bean creation, if such a profile is not active.
@@ -857,7 +857,7 @@ Consequently, if you do not explicitly set the `reply-timeout`, your gateway met
So, to make sure you analyze your flow and if there is even a remote possibility of one of these scenarios to occur, you should set the `reply-timeout` attribute to a "'safe'" value.
Even better, you can set the `requires-reply` attribute of the downstream component to 'true' to ensure a timely response, as produced by the throwing of an exception as soon as that downstream component returns null internally.
However, you should also realize that there are some scenarios (see <<long-running-process-downstream,the first one>>) where `reply-timeout` does not help.
That means it is also important to analyze your message flow and decide when to use a synchronous gateway rather than an asynchrnous gateway.
That means it is also important to analyze your message flow and decide when to use a synchronous gateway rather than an asynchronous gateway.
As <<async-gateway,described earlier>>, the latter case is a matter of defining gateway methods that return `Future` instances.
Then you are guaranteed to receive that return value, and you have more granular control over the results of the invocation.
Also, when dealing with a router, you should remember that setting the `resolution-required` attribute to 'true' results in an exception thrown by the router if it can not resolve a particular channel.