spring-projects / spring-integration

Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns (EIP)
http://projects.spring.io/spring-integration/
Apache License 2.0
1.54k stars 1.11k forks source link

Inconsistent behaviour of message handlers depending on style of configuration. #2784

Closed olegz closed 5 years ago

olegz commented 5 years ago

NOTE: First I want too make clear that this is NOT a bug, rather a request for sort of evolutionary enhancement.

In short SI provides two options for configuring consumers:

Option 1:

@ServiceActivator(inputChannel = Processor.INPUT)
public void mh(Message<?> value) throws Exception {
    . . .
}

Option 2:

@Bean
@ServiceActivator(inputChannel = Processor.INPUT)
public MessageHandler mh() {
       . . .
}

While the end result is the same (you end up with a valid consumer), the inner workings of those consumers are quite different. The main issue is that the consumer from Option 1 will go through the process of type conversion if need to which is decided by Argument Resolvers, while the one (Option 2) may not and that depends and is kind of a point that goes to the core of this issue. . .

The described behaviour has been there from the beginning, however it is my believe that it is time for it to evolve and here is why:

MessageHandler is effectively a type-less Consumer. In fact it enforces and ensures typelessens, so one may argue that not sending it through the process of argument resolution is an appropriate thing to do. However, one may also argue about reasons other then type to initiate some type of conversion. For example one such reason is to represent message payload as human readable text (e.g., String) if it’s content-type is textual (e.g., application/json, text/plain etc), yet argument type is wild card. Another example is more general where the argument is about the actual value of enforcing typelessnes all together. . . is there any? Further more, why shouldn't the following be a valid consumer definition (although a matter of separate issue perhaps)?:

@Bean
@ServiceActivator(inputChannel = Processor.INPUT)
public Consumer<String> mh() {
       . . .
}

vs.

@Bean
@ServiceActivator(inputChannel = Processor.INPUT)
public Consumer<?> mh() {
       . . .
}

After all both MessageHandler and Consumer are FunctionalInterfaces that are effectively identical

Give the fact that argument resolvers are strategies that could be implemented/changed by users especially after this commit, it is my believe that we should always delegate to argument resolvers as a SINGLE extension point where user/frameworks may choose how to treat type-less invocation.

olegz commented 5 years ago

We had a discussion and it became apparent that MessageHandler/Source etc are strategies to mainly support internal features of the framework and thus were not designed to present the level of flexibility that may be expected from application-level strategies designed for the end user. Also, the following actually does work:

@Bean
@ServiceActivator(inputChannel = Processor.INPUT)
public Consumer<?> mh() {
       . . .
}

We have discovered/discussed a few minor issues and potential improvements for it, but those are out of scope of this issue. Closing