Affects: 5.2.0


I configured MappingJackson2MessageConverter, however the app still fails with MessageConversionException.

When I replace @SendTo with template.convertAndSend(), everything works as expected.

Code to reproduce:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.annotation.JmsListenerConfigurer;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;

@SpringBootApplication
@EnableJms
@RequiredArgsConstructor
@Slf4j
public class TestApp implements CommandLineRunner, JmsListenerConfigurer {

  private final JmsMessagingTemplate template;

  @JmsListener(destination = "queue1")
  @SendTo("queue2")
  public Payload handle(Payload payload) {
    log.info("Handling message {}", payload);
    return payload;
  }

  @Bean
  public MessageConverter messageConverter() {
    return new MappingJackson2MessageConverter();
  }

  @Bean
  public DefaultMessageHandlerMethodFactory handlerMethodFactory() {
    DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
    factory.setMessageConverter(messageConverter());
    return factory;
  }

  @Override
  public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
    registrar.setMessageHandlerMethodFactory(handlerMethodFactory());
  }

  @Override
  public void run(String... args) {
    template.setMessageConverter(messageConverter());
    template.convertAndSend("queue1", new Payload("test"));
  }

  public static void main(String[] args) {
    SpringApplication.run(TestApp.class, args);
  }

  @Data
  @AllArgsConstructor
  @NoArgsConstructor
  private static class Payload {

    private String value;
  }
}

Comment From: sbrannen

@b-dzoba, did this work for you on a previous version of the Spring Framework, and if so which version?

Comment From: b-dzoba

@sbrannen I haven't tried with different versions. Is there something wrong with my configuration?

5.1.2. doesn't work too.

Comment From: sbrannen

@sbrannen I haven't tried with different versions.

I was asking about that, because I wanted to know if you were experiencing a regression possibly introduced in 5.2.

5.1.2. doesn't work too.

OK. Thanks for letting us know.

Is there something wrong with my configuration?

I'm not sure off the top of my head. One of us will have to look into it in greater detail to determine that.

Comment From: b-dzoba

Seems like the problem is with MessagingMessageListenerAdapter which doesn't call messageConverter before sending reply. Workaround is to override handleResult() in MessagingMessageListenerAdapter like this

public static class CustomMessagingMessageListenerAdapter extends MessagingMessageListenerAdapter {
    private final MessageConverter messageConverter = new MappingJackson2MessageConverter();
    private final JmsHeaderMapper jmsHeaderMapper = new SimpleJmsHeaderMapper();
    @Override
    protected void handleResult(Object result, javax.jms.Message request, Session session) {
        Message<?> resultMessage;
        if (result instanceof org.springframework.messaging.Message) {
            resultMessage = messageConverter.toMessage(((org.springframework.messaging.Message) result).getPayload(), ((org.springframework.messaging.Message) result).getHeaders());
        } else {
            resultMessage = messageConverter.toMessage(result, jmsHeaderMapper.toHeaders(request));
        }
        super.handleResult(resultMessage, request, session);
    }
}

Comment From: rstoyanchev

@b-dzoba, I think this is where it should be applying message conversion on the return value. Can you try a breakpoint to see if it has the right converter and if so what actually happens there? The converter should be getting set over here.

Comment From: b-dzoba

@rstoyanchev

Can you try a breakpoint to see if it has the right converter

The converter is null, but this is a org.springframework.jms.support.converter.MessageConverter. And I configured a org.springframework.messaging.converter.MessageConverter, because it's required for @JmsListener (DefaultMessageHandlerMethodFactory). Shouldn't @SendTo be able to use the same converter as @JmsListener?

Comment From: snicoll

@b-dzoba the converter is shared for incoming messages and replies but it's null so that's a sign of an inconsistent setup. Why don't you configure the messageConverter on the JmsListenerContainerFactory as indicated in the documentation?

A Spring Boot application does most of the heavy lifting for you anyway, see the documentation. In short, if you expose a org.springframework.jms.support.converter.MessageConverter bean, it's going to be detected and used automatically.

I don't understand why that DefaultMessageHandlerMethodFactory bean is defined. If the above doesn't help, please share a sample we can actually run (rather than code in text).

Comment From: b-dzoba

Why don't you configure the messageConverter on the JmsListenerContainerFactory as indicated in the documentation?

@snicoll Because I use org.springframework.messaging.converter.MappingJackson2MessageConverter for conversion and it doesn't implement org.springframework.jms.support.converter.MessageConverter. This configuration works with @JmsListener but stops working when I add @SendTo

org.springframework.jms.support.converter.MessageConverter bean, it's going to be detected and used automatically

yes, but it doesn't detect org.springframework.messaging.converter.MessageConverter bean, so I have to set it manually on the factory

please share a sample we can actually run

https://github.com/b-dzoba/spring-jms-demo/blob/master/src/main/java/com/example/demo/Issue23886.java

Comment From: mbolis

I bumped into the same issue, is this being taken care of?

Comment From: snicoll

Unfortunately, https://github.com/b-dzoba/spring-jms-demo is no longer accessible.

@b-dzoba or @mbolis would you be able to share a sample we can run ourselves. That would be very helpful.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.