From f043d6ca0bae9ab958f52c90883eb59f921ef5f0 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 14 Feb 2017 15:29:34 -0500 Subject: [PATCH] INT-4228 Fix Hidden Channel Bean Definition Error JIRA: https://jira.spring.io/browse/INT-4228 Previously, if a bean definition for a channel exists, but has configuration issues, the `AbstractMethodAnnotationPostProcessor` still went ahead and created a `DirectChannel`. Only with TRACE logging was the root cause apparent. This was because all `BeanException` s cause that behavior. Now, only `NoSuchBeanDefinitionException` will cause auto-creation of channels. Tested with mocks and a real Boot app, which now correctly reports ``` 15:28:41.582 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'rabbitConnectionFactory' available ``` --- ...AbstractMethodAnnotationPostProcessor.java | 12 ++- .../channel/BeanFactoryChannelResolver.java | 7 +- ...tionPostProcessorChannelCreationTests.java | 92 +++++++++++++++++++ 3 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorChannelCreationTests.java 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 a9175f2420..48c840be07 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 @@ -292,9 +292,14 @@ public abstract class AbstractMethodAnnotationPostProcessor annotations) { AbstractEndpoint endpoint; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/channel/BeanFactoryChannelResolver.java b/spring-integration-core/src/main/java/org/springframework/integration/support/channel/BeanFactoryChannelResolver.java index 0afe61c6c3..c2e3aa39df 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/channel/BeanFactoryChannelResolver.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/channel/BeanFactoryChannelResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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 org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.core.DestinationResolutionException; @@ -88,6 +89,10 @@ public class BeanFactoryChannelResolver implements DestinationResolver invocation.getArgument(0)) + .given(beanFactory).initializeBean(any(DirectChannel.class), eq("channel")); + willAnswer(invocation -> invocation.getArgument(0)) + .given(beanFactory).initializeBean(any(MessageHandler.class), eq("foo.foo.serviceActivator.handler")); + MessagingAnnotationPostProcessor mapp = new MessagingAnnotationPostProcessor(); + mapp.setBeanFactory(beanFactory); + mapp.afterPropertiesSet(); + mapp.postProcessAfterInitialization(new Foo(), "foo"); + verify(beanFactory).registerSingleton(eq("channel"), any(DirectChannel.class)); + } + + @Test + public void testDontCreateChannelWhenChannelHasBadDefinition() { + ConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class); + given(beanFactory.getBean("channel", MessageChannel.class)).willThrow(BeanCreationException.class); + willAnswer(invocation -> invocation.getArgument(0)) + .given(beanFactory).initializeBean(any(DirectChannel.class), eq("channel")); + willAnswer(invocation -> invocation.getArgument(0)) + .given(beanFactory).initializeBean(any(MessageHandler.class), eq("foo.foo.serviceActivator.handler")); + MessagingAnnotationPostProcessor mapp = new MessagingAnnotationPostProcessor(); + mapp.setBeanFactory(beanFactory); + mapp.afterPropertiesSet(); + try { + mapp.postProcessAfterInitialization(new Foo(), "foo"); + fail("Expected a DestinationResolutionException"); + } + catch (DestinationResolutionException e) { + assertThat(e.getMessage(), + containsString("A bean definition with name 'channel' exists, but failed to be created")); + } + } + + public static class Foo { + + @ServiceActivator(inputChannel = "channel") + public void foo(String in) { + // empty + } + + } + +}