I can write instances of multiple types to a given destination, e.g.:
JmsTemplate template = ...
Alpha alpha = new Alpha(...);
Beta beta = new Beta(...);
template.convertAndSend("my-destination", alpha);
template.convertAndSend("my-destination", beta);
I thought I'd then be able to provide multiple @JmsListener
annotated methods to receive the different message payloads - like so:
@JmsListener(destination = "my-destination")
public void receiveAlpha(Alpha alpha) { ... }
@JmsListener(destination = "my-destination")
public void receiveBeta(Beta beta) { ... }
But if I try this I get exceptions in PayloadArgumentResolver.resolveArgument
as it can't distinguish that Beta
values should be sent to one method and Alpha
values to another.
How should I be handling this? As I encode the payload type as a message property I can specify a selector to get things to work like so:
@JmsListener(destination = "my-destination", selector = "_type = 'Alpha'")
public void receiveAlpha(Alpha alpha) { ... }
@JmsListener(destination = "my-destination", selector = "_type = 'Beta'")
public void receiveBeta(Beta beta) { ... }
But as Spring is doing all kinds of cleverness behind the scenes I'm surprised I have to help it out explicitly like this.
Is there a more implicit / better way to do this?
JmsListener
doesn't support method routing - each annotated method gets its own listener container.
The only other alternative is to use ...(Object object)
and downcast yourself.
You could set the JmsTemplate's message converter to set the message's Java type into the message's "type" property, and then in the JmsListener, configure the selector for receiving only the desired message type.
Below is an example in Kotlin, and Java should be the same
The default message convert, annotates the message type into "type" property:
@Bean // Serialize message content to json using TextMessage
fun jacksonJmsMessageConverter(): MessageConverter {
val converter = MappingJackson2MessageConverter()
converter.setTargetType(MessageType.TEXT)
converter.setTypeIdPropertyName("type")
return converter
}
With the annotating message converter, JMS listener could specify message type in selector:
// Uses default JmsListenerContainerFactory
@JmsListener(destination = "mailbox", containerFactory = "myFactory", selector="type='com.garnetsoft.sf.service.queue.CopyFolderJob'")
fun receiveMessage(job: CopyFolderJob) {
println("Received copy job <$job>")
}
@JmsListener(destination = "mailbox", containerFactory = "myFactory", selector="type='com.garnetsoft.sf.service.queue.CutFolderJob'")
fun receiveMessage(job: CutFolderJob) {
println("Received cut job <$job>")
}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With