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:
Artem Bilan
2019-07-17 15:11:10 -04:00
committed by Gary Russell
parent ebb22c2ed4
commit c712416b63
25 changed files with 330 additions and 202 deletions

View File

@@ -289,7 +289,7 @@ public class ConnectionEventTests {
String actual = theEvent.toString();
assertThat(actual).contains("cause=java.net.BindException");
assertThat(actual).contains("source="
+ "sf, port=" + factory.getPort());
+ "bean 'sf', port=" + factory.getPort());
ArgumentCaptor<String> reasonCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);

View File

@@ -240,7 +240,7 @@ public class ConnectionFactoryTests {
assertThat(n < 200).as("Stop was not invoked in time").isTrue();
latch2.countDown();
assertThat(latch3.await(10, TimeUnit.SECONDS)).as("missing debug log").isTrue();
String expected = "foo, port=" + factory.getPort() + message;
String expected = "bean 'foo', port=" + factory.getPort() + message;
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger, atLeast(1)).debug(captor.capture());
assertThat(captor.getAllValues()).contains(expected);