0

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.

  • Add a `MessagePostProcessor` to the factory configuring your listener. That way you can add whatever you want. – M. Deinum Jun 28 '18 at 18:26
  • Can you show some snippet? I tries it already, but had lot of trouble with it together with the JmsListener support classes. – Adriano dos Santos Fernandes Jun 28 '18 at 19:29
  • I was used to Rabbit and wrongly assumed you could use the same approach with JMS, however you cannot. What you could do is create a `MessageConverter` which does what you want, that will be automatically wired to all of your jms listeners to convert the response. I assume you already have configured one (a marshalling converter I guess). You could wrap this in another one that adds the headers to the messages. – M. Deinum Jun 28 '18 at 19:59

1 Answers1

0

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");
    }

}
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • That instance is created with `new MessagingMessageListenerAdapter()` inside `MethodJmsListenerEndpoint.createMessageListenerInstance`. This is why I'm saying the difficult to use together with @JmsListener. It's not a replaceable bean in that context. – Adriano dos Santos Fernandes Jun 28 '18 at 19:48
  • Right, that `createMessageListenerInstance()` has the code to propagate a `MessageConverter` from the provided `MessageListenerContainer` to the created `MessagingMessageListenerAdapter`. – Artem Bilan Jun 28 '18 at 19:51
  • You could actually use a `MessageConverter` as that constructs the message including and would allow you to set the header. You could create a Header adding message converter which wraps the actual converter and after calling the delegate add the headers. – M. Deinum Jun 28 '18 at 19:57
  • See an UPDATE in my answer, please. – Artem Bilan Jun 28 '18 at 20:06
  • I my case (using JAXB) I overrided org.springframework.jms.support.converter.MarshallingMessageConverter's toMessage and it worked. Thanks. – Adriano dos Santos Fernandes Jun 29 '18 at 13:46