GH-2748: Add bean definition info into exceptions (#2986)
* GH-2748: Add bean definition info into exceptions Fixes https://github.com/spring-projects/spring-integration/issues/2748 In many cases Spring Integration stack traces doesn't contain any relations to end-user code. Just because a target project code mostly contains only a configuration for out-of-the-box components without any custom code. When exception is thrown from such an out-of-the-box component, it is hard from the stack trace to determine a configuration source for those components. * Add a logic into the `IntegrationObjectSupport` to obtain a its own `BeanDefinition` from the `BeanFactory` to include a `resource` and `source` (if any) into the `toString()` representation, as well as add a new `getBeanDescription()` to get such an info at runtime * The `toString()` is simply used by `this` reference in the message for `MessagingException` thrown from the `IntegrationObjectSupport` implementations * Modify an exception message for the `MessageTransformingHandler` and `MessageFilter` to make it based on `this`. The `AbstractMessageHandler` already includes `this` into its exception message * Modify a `AbstractConsumerEndpointParser` and `AbstractAmqpInboundAdapterParser` (as a sample) to include a `resource` and `source` into a `MessageHandler` `BeanDefinition`. * Include an `IntegrationFlow` `BeanDefinition` `resource` (`@Configuration` class) and its bean method as a `source` into all child beans declared during flow parsing in the `IntegrationFlowBeanPostProcessor` * Add `IntegrationFlowRegistrationBuilder.setSource()` for manually registered flows: there is no configuration parsing phase to extract such an info from `BeanFactory` * Propagate that `source` into all the child beans provided by the `IntegrationFlow` * Modify a `LambdaMessageProcessor` exception message to include a method info in case of `InvocationTargetException` * Do not cast explicitly for `ConfigurableListableBeanFactory` in the `IntegrationObjectSupport` to avoid tests modifications for mocking directly into `ConfigurableListableBeanFactory`. Use `instanceof` instead in the `getBeanDescription()` * * Fix Checkstyle issues * * Fix `IntegrationGraphServer` and `IntegrationMBeanExporter` to rely on the `NamedComponent` for channel names instead of always call `toString()` which is now much more than just a bean name * Don't describe a `componentName` if it is the same as a `beanName` * Check for parent `BeanDefinition` in the `IntegrationFlowBeanPostProcessor` before calling its meta-info * Fix tests according new `IntegrationObjectSupport.toString()` behavior
This commit is contained in:
committed by
Gary Russell
parent
ebb22c2ed4
commit
c712416b63
@@ -25,6 +25,7 @@ import org.w3c.dom.Element;
|
||||
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -103,7 +105,7 @@ abstract class AbstractAmqpInboundAdapterParser extends AbstractSingleBeanDefini
|
||||
builder.addConstructorArgReference(listenerContainerRef);
|
||||
}
|
||||
else {
|
||||
BeanDefinition listenerContainerBeanDef = this.buildListenerContainer(element, parserContext);
|
||||
BeanDefinition listenerContainerBeanDef = buildListenerContainer(element, parserContext);
|
||||
builder.addConstructorArgValue(listenerContainerBeanDef);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converter");
|
||||
@@ -117,11 +119,12 @@ abstract class AbstractAmqpInboundAdapterParser extends AbstractSingleBeanDefini
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase");
|
||||
this.configureChannels(element, parserContext, builder);
|
||||
configureChannels(element, parserContext, builder);
|
||||
AbstractBeanDefinition adapterBeanDefinition = builder.getRawBeanDefinition();
|
||||
adapterBeanDefinition.setResource(parserContext.getReaderContext().getResource());
|
||||
adapterBeanDefinition.setSource(IntegrationNamespaceUtils.createElementDescription(element));
|
||||
}
|
||||
|
||||
protected abstract void configureChannels(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||
|
||||
private BeanDefinition buildListenerContainer(Element element, ParserContext parserContext) {
|
||||
if (!element.hasAttribute("queue-names")) {
|
||||
parserContext.getReaderContext().error("If no 'listener-container' reference is provided, " +
|
||||
@@ -163,7 +166,7 @@ abstract class AbstractAmqpInboundAdapterParser extends AbstractSingleBeanDefini
|
||||
|
||||
private void assertNoContainerAttributes(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
List<String> allContainerAttributes = new ArrayList<String>(Arrays.asList(CONTAINER_VALUE_ATTRIBUTES));
|
||||
List<String> allContainerAttributes = new ArrayList<>(Arrays.asList(CONTAINER_VALUE_ATTRIBUTES));
|
||||
allContainerAttributes.addAll(Arrays.asList(CONTAINER_REFERENCE_ATTRIBUTES));
|
||||
for (String attributeName : allContainerAttributes) {
|
||||
if (StringUtils.hasText(element.getAttribute(attributeName))) {
|
||||
@@ -173,4 +176,7 @@ abstract class AbstractAmqpInboundAdapterParser extends AbstractSingleBeanDefini
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void configureChannels(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user