Reputation: 2006
I am new to JMS and had a requirement to batch requests for a listener to handle. Link: http://sleeplessinslc.blogspot.in/2010/04/batchmessagelistenercontainer-using.html gives a good solution. I am stuck in implementing the same. Instead of using the default container, I overwrote the container-class to use this new class:
<jms:listener-container container-class="org.bsnyder.spring.jms.listener.BatchMessageListenerContainer"
acknowledge="transacted">
<jms:listener destination="CHANDRA.BATCHTEST" ref="messageListener" />
</jms:listener-container>
<bean id="messageListener" class="org.bsnyder.spring.jms.listener.BatchMessageListener" />
Here the BatchMessageListener is extending SessionAwareBatchMessageListener as mentioned in the blog.
Error I get is:
[ERROR] PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'messageListener' threw exception;
nested exception is java.lang.IllegalArgumentException: Message listener needs to be of type [org.bsnyder.spring.jms.listener.SessionAwareBatchMessageListener]:
Failed properties: Property 'messageListener' threw exception; nested exception is java.lang.IllegalArgumentException: Message listener needs to be of type [org.bsnyder.spring.jms.listener.SessionAwareBatchMessageListener]
Should I change the container-type (which is "default" by default)? http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/jms.html doesn't contain details on how to set this.
Upvotes: 3
Views: 3329
Reputation: 11
Why do you need to read messages in batch from a queue? In such a case I strongly recommend you to use spring batch instead of writing a custom batch listener. Spring batch is easily configurable.
Upvotes: 1
Reputation: 3120
The problem is that the jms namespace parser is creating an instance of org.springframework.jms.listener.adapter.MessageListenerAdapter
with a delegate
property that references your org.bsnyder.spring.jms.listener.BatchMessageListener
instance. Therefore, in your checkMessageListener()
method of BatchMessageListenerContainer
, you need to change this:
protected void checkMessageListener(Object messageListener) {
if (!(messageListener instanceof SessionAwareBatchMessageListener)) {
throw new IllegalArgumentException("Message listener needs to be of type ["
+ SessionAwareBatchMessageListener.class.getName() + "]");
}
}
...to this:
protected void checkMessageListener(Object messageListener) {
if (!(messageListener instanceof MessageListenerAdapter)) {
throw new IllegalArgumentException("Message listener needs to be of type ["
+ MessageListenerAdapter.class.getName() + "]");
}
}
Although, this really doesn't buy you much in terms of validation of your loaded classes. It's also unfortunate that the getDelegate()
method of MessageListenerAdapter
is protected; otherwise, you could do your check against the delegate's type, which should be an instance of your custom SessionAwareBatchMessageListener
. I suppose you could use reflection. Alternatively, you could avoid using the jms namespace and create your own custom BatchMessageListenerAdapter
that implements SessionAwareBatchMesageListener
and extends MessageListenerAdapter
and use that custom adapter instead of the jms namespace's default implementation. (There is no way to override this default using the namespace btw.) Ultimately, it boils down to if you REALLY need that load-time validation or not.
If you wanted to skip validation, just do this instead:
protected void checkMessageListener(Object messageListener) {
// Do nothing...
}
That will allow your app to load without issue.
Upvotes: 1