From e9c554534a8bd965865e575960711b46b8262dd8 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 16 Nov 2018 16:17:03 -0500 Subject: [PATCH] INT-4556: Fix messaging anns for FactoryBeans JIRA: https://jira.spring.io/browse/INT-4556 We definitely need to resolve a `@Bean` method to the target object to be sure do not create a new `MessageHandler` bean. **Cherry-pick to 5.0.x** --- ...AbstractMethodAnnotationPostProcessor.java | 24 +++++++++---------- .../BridgeFromAnnotationPostProcessor.java | 8 ++++++- .../MessagingAnnotationPostProcessor.java | 24 +++++++++---------- ...rviceActivatorAnnotationPostProcessor.java | 4 ++-- .../configuration/EnableIntegrationTests.java | 17 +++++++++---- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java index a1a96f698b..81f6459f58 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java @@ -139,16 +139,13 @@ public abstract class AbstractMethodAnnotationPostProcessor annotations) { - if (this.beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) { + Object sourceHandler = null; + if (beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) { if (!this.beanFactory.containsBeanDefinition(resolveTargetBeanName(method))) { this.logger.debug("Skipping endpoint creation; perhaps due to some '@Conditional' annotation."); return null; } - } - - Object sourceHandler = null; - if (beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) { - if (MessageHandler.class.isAssignableFrom(method.getReturnType())) { + else { sourceHandler = resolveTargetBeanFromMethodWithBeanAnnotation(method); } } @@ -170,12 +167,15 @@ public abstract class AbstractMethodAnnotationPostProcessor { @@ -78,4 +79,9 @@ public class BridgeFromAnnotationPostProcessor extends AbstractMethodAnnotationP return handler; } + @Override + protected Object resolveTargetBeanFromMethodWithBeanAnnotation(Method method) { + return null; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java index 8bc7c46823..ab03363f1c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java @@ -75,13 +75,11 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean protected final Log logger = LogFactory.getLog(this.getClass()); // NOSONAR - private final Map, MethodAnnotationPostProcessor> postProcessors = - new HashMap, MethodAnnotationPostProcessor>(); + private final Map, MethodAnnotationPostProcessor> postProcessors = new HashMap<>(); private ConfigurableListableBeanFactory beanFactory; - private final Set> noAnnotationsCache = - Collections.newSetFromMap(new ConcurrentHashMap, Boolean>(256)); + private final Set> noAnnotationsCache = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); @Override public void setBeanFactory(BeanFactory beanFactory) { @@ -99,7 +97,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean Assert.notNull(this.beanFactory, "BeanFactory must not be null"); ((BeanDefinitionRegistry) this.beanFactory).registerBeanDefinition( IntegrationContextUtils.DISPOSABLES_BEAN_NAME, - BeanDefinitionBuilder.genericBeanDefinition(Disposables.class, () -> new Disposables()) + BeanDefinitionBuilder.genericBeanDefinition(Disposables.class, Disposables::new) .getRawBeanDefinition()); this.postProcessors.put(Filter.class, new FilterAnnotationPostProcessor(this.beanFactory)); this.postProcessors.put(Router.class, new RouterAnnotationPostProcessor(this.beanFactory)); @@ -229,13 +227,15 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean */ protected List getAnnotationChain(Method method, Class annotationType) { Annotation[] annotations = AnnotationUtils.getAnnotations(method); - List annotationChain = new LinkedList(); - Set visited = new HashSet(); - for (Annotation ann : annotations) { - recursiveFindAnnotation(annotationType, ann, annotationChain, visited); - if (annotationChain.size() > 0) { - Collections.reverse(annotationChain); - return annotationChain; + List annotationChain = new LinkedList<>(); + if (annotations != null) { + Set visited = new HashSet<>(); + for (Annotation ann : annotations) { + recursiveFindAnnotation(annotationType, ann, annotationChain, visited); + if (annotationChain.size() > 0) { + Collections.reverse(annotationChain); + return annotationChain; + } } } return annotationChain; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/ServiceActivatorAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/ServiceActivatorAnnotationPostProcessor.java index f08ca4ade4..f5779bf6e1 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/ServiceActivatorAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/ServiceActivatorAnnotationPostProcessor.java @@ -52,8 +52,8 @@ public class ServiceActivatorAnnotationPostProcessor extends AbstractMethodAnnot protected MessageHandler createHandler(Object bean, Method method, List annotations) { AbstractReplyProducingMessageHandler serviceActivator; if (AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) { - final Object target = this.resolveTargetBeanFromMethodWithBeanAnnotation(method); - serviceActivator = this.extractTypeIfPossible(target, AbstractReplyProducingMessageHandler.class); + final Object target = resolveTargetBeanFromMethodWithBeanAnnotation(method); + serviceActivator = extractTypeIfPossible(target, AbstractReplyProducingMessageHandler.class); if (serviceActivator == null) { if (target instanceof MessageHandler) { /* diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 1d98b6b74c..efb28cf7ca 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -111,6 +111,7 @@ import org.springframework.integration.endpoint.MethodInvokingMessageSource; import org.springframework.integration.endpoint.PollingConsumer; import org.springframework.integration.expression.SpelPropertyAccessorRegistrar; import org.springframework.integration.gateway.GatewayProxyFactoryBean; +import org.springframework.integration.handler.ServiceActivatingHandler; import org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice; import org.springframework.integration.history.MessageHistory; import org.springframework.integration.history.MessageHistoryConfigurer; @@ -421,11 +422,17 @@ public class EnableIntegrationTests { assertEquals("FOO", message.getHeaders().get("foo")); MessagingTemplate messagingTemplate = new MessagingTemplate(this.controlBusChannel); - assertFalse(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); - this.controlBusChannel.send(new GenericMessage("@lifecycle.start()")); - assertTrue(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); - this.controlBusChannel.send(new GenericMessage("@lifecycle.stop()")); - assertFalse(messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); + assertEquals(false, messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); + this.controlBusChannel.send(new GenericMessage<>("@lifecycle.start()")); + assertEquals(true, messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); + this.controlBusChannel.send(new GenericMessage<>("@lifecycle.stop()")); + assertEquals(false, messagingTemplate.convertSendAndReceive("@lifecycle.isRunning()", Boolean.class)); + + Map beansOfType = + this.context.getBeansOfType(ServiceActivatingHandler.class); + + assertFalse(beansOfType.keySet() + .contains("enableIntegrationTests.ContextConfiguration2.controlBus.serviceActivator.handler")); } @Test