Closed spring-operator closed 9 years ago
Dave Syer commented
It seems like overriding handleResult()
gives a lot of flexibility (but possibly not enough?), so I'm tempted to resolve as Won't Fix. Any other opinions?
Albert-Jan de Vries commented
I've got the following MessageHandler class:
public Result handleMessage(Input input) { // TODO how should this work? if (messageContainsReplyTo(messageProperties)) {
return processInput(input);
}
else
{
LOG.error("Message doesn't contain a replyTo address, so nothing happend!");
return null;
}
}
And changed it this way:
public Result handleMessage(Input input, MessageProperties messageProperties)
By changing the MessageListenerAdapter onMessage methode:
line: 343
Object[] listenerArguments = new Object[] { buildListenerArguments(convertedMessage)[0], message.getMessageProperties() };
Dave Syer commented
I think we should plan to tackle this more comprehensively in 1.1, since it is not impossible with 1.0. Note to readers: the approach above is not thread safe (so stick to just overriding existing methods).
Daniel commented
I have a very similar issue in the sense that I was also wondering how to access the Message headers: http://forum.spring.io/forum/spring-projects/integration/amqp/725218-demultiplexing-messages-from-topic-exchange?_=1383385438137&_=1383387113713
Perhaps a simple resolution could be the following: ////// org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter:
Object[] listenerArguments = buildListenerArguments(convertedMessage); ++ Object[] listenerArguments = buildListenerArguments(convertedMessage, message);
protected Object[] buildListenerArguments(Object extractedMessage) { ++ protected Object[] buildListenerArguments(Object extracted, Message message) { //////
This allows us to override the adapter (specifically, buildListenerArguments), take whatever we need from the message, and send it on as additional parameter(s).
N.B. Gary (Russell) suggested an even nicer solution along the way of supporting the following (but I don't know what code changes to propose to build that):
public void handleMessage(@ConvertedPayload
Foo foo, @Property
("bar") String bar) {
...
}
Gary Russell commented
Another (quick) user work-around is to create a custom message converter; subclass SimpleMessageConverter
, in fromMessage()
, call super.fromMessage()
then populate a POJO with the converted result plus any additional message properties the listener might be interested in.
Daniel commented
Gary: you suggested this workaround on the forum as well, but as I replied it creates new problems for the serverside handler.
Suppose the client has 10 different POJOs it can send to the server, e.g. HelloRequest, ServiceRequest, etc.. The server has a handler POJO with handleMessage(HelloRequest request), handleMessage(ServiceRequest) etc.. If you do as you suggested, you will have to either: A) define a new POJO for each of the client requests that wraps the original client object and has the necessary additional field(s) (and then change the various handleMessage methods to accept the wrapped types B) define 1 generic wrapper that wraps all the possible client request
A) results in a bunch of duplication and B) breaks the serverside handler b/c you can then only have 1 handleMessage(Wrapper w) that needs to unwrap and reroute (using instanceof) to 10 different methods. Either option is far from elegant, right? (my 2 line suggestion specifically avoids these problems).
Gary Russell commented
I don't disagree with the basic premise; and I agree we can enhance the adapter; I am just trying to provide a quick work-around.
For B), you can use a simple Map<String, Object> as the argument, where the map has 'convertedMessage' and other keys.
But, I agree, you'd need to do some routing based on the type. If you bring the abstraction up a level (as I also suggested in the forum) using Spring integration would do exactly what you want.
amqp-inbound-adapter->channel->service-activator
Where the service activator is defined as a POJO that implements something like...
public interface MyService {
public fooHandler(Foo foo, @Header("bar") String bar, @Header("baz") String baz);
public barHandler(Bar bar, @Header("baz") String baz, @Header("qux") String qux);
...
}
And Spring Integration will take care of invoking the appropriate method, based on the payload type.
Artem Bilan commented
The is fixed with the POJO method-level @RabbitListener
which is based on the Spring Messaging, where @Payload
and @Header
annotation come to the rescue.
Also see the linked issue #2001, how the same @RabbitListener
can be used to route message to the appropriate method with @RabbitHandler
for specific payload
type.
Dave Syer opened AMQP-180 and commented
Useful forum discussion: http://forum.springsource.org/showthread.php?111630-Get-message-info-in-handleMessage-class
Affects: 1.0.0.RC2
Issue Links:
2001 Multiple POJO message types on same channel