Skip to content

Commit 60db7bc

Browse files
artembilangaryrussell
authored andcommitted
INT-4518: Channel late-binding in Messaging Anns
JIRA: https://jira.spring.io/browse/INT-4518 * Fix `BridgeFromAnnotationPostProcessor` do not resolve `outputChannel` for the target `BridgeHandler` * Rework logic in the `AbstractMethodAnnotationPostProcessor` to do not resolve a `MessageHandler` bean from the `@Bean` method when we can just check a method return type. * Check `BeanDefinition` instead of real bean when we consult for conditions **Cherry-pick to 5.0.x**
1 parent e2b398a commit 60db7bc

File tree

3 files changed

+116
-25
lines changed

3 files changed

+116
-25
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public abstract class AbstractMethodAnnotationPostProcessor<T extends Annotation
9898

9999
protected final Log logger = LogFactory.getLog(this.getClass());
100100

101-
protected final List<String> messageHandlerAttributes = new ArrayList<String>();
101+
protected final List<String> messageHandlerAttributes = new ArrayList<>();
102102

103103
protected final ConfigurableListableBeanFactory beanFactory;
104104

@@ -129,23 +129,21 @@ public AbstractMethodAnnotationPostProcessor(ConfigurableListableBeanFactory bea
129129
@Override
130130
public Object postProcess(Object bean, String beanName, Method method, List<Annotation> annotations) {
131131
if (this.beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) {
132-
try {
133-
resolveTargetBeanFromMethodWithBeanAnnotation(method);
134-
}
135-
catch (NoSuchBeanDefinitionException e) {
136-
if (this.logger.isDebugEnabled()) {
137-
this.logger.debug("Skipping endpoint creation; "
138-
+ e.getMessage()
139-
+ "; perhaps due to some '@Conditional' annotation.");
140-
}
132+
if (!this.beanFactory.containsBeanDefinition(resolveTargetBeanName(method))) {
133+
this.logger.debug("Skipping endpoint creation; perhaps due to some '@Conditional' annotation.");
141134
return null;
142135
}
143136
}
144137

145-
List<Advice> adviceChain = extractAdviceChain(beanName, annotations);
138+
boolean handlerExists = false;
139+
if (beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) {
140+
handlerExists = MessageHandler.class.isAssignableFrom(method.getReturnType());
141+
}
146142

147143
MessageHandler handler = createHandler(bean, method, annotations);
148144

145+
List<Advice> adviceChain = extractAdviceChain(beanName, annotations);
146+
149147
if (!CollectionUtils.isEmpty(adviceChain) && handler instanceof AbstractReplyProducingMessageHandler) {
150148
((AbstractReplyProducingMessageHandler) handler).setAdviceChain(adviceChain);
151149
}
@@ -169,12 +167,6 @@ public Object postProcess(Object bean, String beanName, Method method, List<Anno
169167
}
170168
}
171169

172-
boolean handlerExists = false;
173-
if (this.beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) {
174-
Object handlerBean = this.resolveTargetBeanFromMethodWithBeanAnnotation(method);
175-
handlerExists = handlerBean != null && handler == handlerBean;
176-
}
177-
178170
if (!handlerExists) {
179171
String handlerBeanName = generateHandlerBeanName(beanName, method);
180172
if (handler instanceof ReplyProducingMessageHandlerWrapper
@@ -228,7 +220,9 @@ public Object postProcess(Object bean, String beanName, Method method, List<Anno
228220
if (endpoint != null) {
229221
return endpoint;
230222
}
231-
return handler;
223+
else {
224+
return handler;
225+
}
232226
}
233227

234228
@Override
@@ -450,14 +444,11 @@ protected Object resolveTargetBeanFromMethodWithBeanAnnotation(Method method) {
450444
}
451445

452446
protected String resolveTargetBeanName(Method method) {
453-
String id = null;
447+
String id = method.getName();
454448
String[] names = AnnotationUtils.getAnnotation(method, Bean.class).name();
455449
if (!ObjectUtils.isEmpty(names)) {
456450
id = names[0];
457451
}
458-
if (!StringUtils.hasText(id)) {
459-
id = method.getName();
460-
}
461452
return id;
462453
}
463454

spring-integration-core/src/main/java/org/springframework/integration/config/annotation/BridgeFromAnnotationPostProcessor.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,8 @@ protected String getInputChannelAttribute() {
7373
@Override
7474
protected MessageHandler createHandler(Object bean, Method method, List<Annotation> annotations) {
7575
BridgeHandler handler = new BridgeHandler();
76-
Object outputChannel = resolveTargetBeanFromMethodWithBeanAnnotation(method);
77-
Assert.isInstanceOf(MessageChannel.class, outputChannel);
78-
handler.setOutputChannel((MessageChannel) outputChannel);
76+
String outputChannelName = resolveTargetBeanName(method);
77+
handler.setOutputChannelName(outputChannelName);
7978
return handler;
8079
}
8180

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.config.annotation;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotNull;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.ComponentScan;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.context.annotation.FilterType;
30+
import org.springframework.integration.annotation.BridgeFrom;
31+
import org.springframework.integration.channel.DirectChannel;
32+
import org.springframework.integration.channel.QueueChannel;
33+
import org.springframework.integration.config.EnableIntegration;
34+
import org.springframework.messaging.Message;
35+
import org.springframework.messaging.MessageChannel;
36+
import org.springframework.messaging.PollableChannel;
37+
import org.springframework.messaging.support.GenericMessage;
38+
import org.springframework.test.context.ContextConfiguration;
39+
import org.springframework.test.context.junit4.SpringRunner;
40+
41+
/**
42+
* @author Artem Bilan
43+
*
44+
* @since 5.0.8
45+
*/
46+
@RunWith(SpringRunner.class)
47+
@ContextConfiguration(classes = BridgeFromIntegrationTests.RootTestConfiguration.class)
48+
public class BridgeFromIntegrationTests {
49+
50+
@Autowired
51+
private MessageChannel gatewayChannel;
52+
53+
@Autowired
54+
private PollableChannel outputChannel;
55+
56+
@Test
57+
public void testBridgeFromConfiguration() {
58+
this.gatewayChannel.send(new GenericMessage<>("world"));
59+
60+
Message<?> receive = this.outputChannel.receive(10_000);
61+
62+
assertNotNull(receive);
63+
assertEquals("hello world", receive.getPayload());
64+
}
65+
66+
67+
@Configuration
68+
@EnableIntegration
69+
@ComponentScan(
70+
basePackageClasses = BridgeFromIntegrationTests.class,
71+
useDefaultFilters = false,
72+
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
73+
classes = { AnnotatedTestService.class, ScannedTestConfiguration.class }))
74+
public static class RootTestConfiguration {
75+
76+
}
77+
78+
@Configuration
79+
public static class ScannedTestConfiguration {
80+
81+
@Bean
82+
@BridgeFrom("gatewayChannel")
83+
public DirectChannel inputChannel() {
84+
return new DirectChannel();
85+
}
86+
87+
88+
@Bean
89+
public DirectChannel gatewayChannel() {
90+
return new DirectChannel();
91+
}
92+
93+
94+
@Bean
95+
public PollableChannel outputChannel() {
96+
return new QueueChannel();
97+
}
98+
99+
}
100+
101+
}

0 commit comments

Comments
 (0)