Search code examples
springspring-bootspring-jmsspring-messaging

Spring Messaging JMS reply interceptor


I have a @JmsListener method that receives a parameter and returns an object instance, all of that working with XML and the JAXB marshalling.

@JmsListener(
    containerFactory = ...,
    destination = ...,
    selector = ...
)
public RunReport.Response run(RunReport runReport) throws Exception
{
    // ...

    RunReport.Response response = new RunReport.Response();
    return response;
}

That works as I want, returning RunReport.Response instead of Message<RunReport.Response>.

But I want to inject JMS headers for the reply for all my JmsListener methods, i.e., I want to do it in a "middleware" (setup in my configuration).

What path I must go to do it? It seems Spring's JmsListener support classes are not configurable to that level.


Solution

  • There is this one:

    /**
     * @see AbstractMessageListenerContainer#setMessageConverter(MessageConverter)
     */
    public void setMessageConverter(MessageConverter messageConverter) {
        this.messageConverter = messageConverter;
    }
    

    On the AbstractJmsListenerContainerFactory you can provide. Actually you only need to provide such a @Bean in the application context since you deal with Spring Boot.

    This one is called from the AbstractAdaptableMessageListener:

    /**
     * Build a JMS message to be sent as response based on the given result object.
     * @param session the JMS Session to operate on
     * @param result the content of the message, as returned from the listener method
     * @return the JMS {@code Message} (never {@code null})
     * @throws JMSException if thrown by JMS API methods
     * @see #setMessageConverter
     */
    protected Message buildMessage(Session session, Object result) throws JMSException {
    

    So, this is indeed a place where you can build your own JMS Message and set its properties and headers.

    UPDATE

    I don't know what am I missing in your requirements, but here how I see it:

    @SpringBootApplication
    public class So51088580Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So51088580Application.class, args);
        }
    
        @Bean
        public MessageConverter messageConverter() {
            return new SimpleMessageConverter() {
    
                @Override
                public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
                    Message message = super.toMessage(object, session);
                    message.setStringProperty("myProp", "bar");
                    return message;
                }
    
            };
        }
    
        @JmsListener(destination = "foo")
        public String jmsHandle(String payload) {
            return payload.toUpperCase();
        }
    
    }
    

    And test-case on the matter:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class So51088580ApplicationTests {
    
        @Autowired
        private JmsTemplate jmsTemplate;
    
        @Test
        public void testReplyWithProperty() throws JMSException {
            Message message = this.jmsTemplate.sendAndReceive("foo", session -> session.createTextMessage("foo"));
    
            assertThat(message).isInstanceOf(TextMessage.class);
            TextMessage textMessage = (TextMessage) message;
            assertThat(textMessage.getText()).isEqualTo("FOO");
            assertThat(textMessage.getStringProperty("myProp")).isEqualTo("bar");
        }
    
    }