Spring jms invokes the wrong listener method when receiving a message

Viewed 20

I am playing with Spring-boot and jms message driven beans.

I installed Apache ActiveMQ.

One queue is being used on which different message types are being send and read.

One simple MessageConverter was written to convert a POJO instance into XML.

A property Class was set in the message to determine how to convert a message to a POJO:


@Component
@Slf4j
public class XMLMessageConverter implements MessageConverter {
    
    private static final String CLASS_NAME = "Class";

    private final Map<Class<?>, Marshaller> marshallers = new HashMap<>();

    @SneakyThrows
    private Marshaller getMarshallerForClass(Class<?> clazz) {
        marshallers.putIfAbsent(clazz, JAXBContext.newInstance(clazz).createMarshaller());
        Marshaller marshaller = marshallers.get(clazz);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        return marshaller;
    }

    @Override
    public Message toMessage(@NonNull Object object, Session session) throws JMSException, MessageConversionException {
        try {
            Marshaller marshaller = getMarshallerForClass(object.getClass());
            StringWriter stringWriter = new StringWriter();
            marshaller.marshal(object, stringWriter);
            TextMessage message = session.createTextMessage();
            log.info("Created message\n{}", stringWriter);
            message.setText(stringWriter.toString());
            message.setStringProperty(CLASS_NAME, object.getClass().getCanonicalName());
            return message;
        } catch (JAXBException e) {
            throw new MessageConversionException(e.getMessage());
        }
    }

    @Override
    public Object fromMessage(@NonNull Message message) throws JMSException, MessageConversionException {
        TextMessage textMessage = (TextMessage) message;
        String payload = textMessage.getText();
        String className = textMessage.getStringProperty(CLASS_NAME);
        log.info("Converting message with id {} and {}={}into java object.", message.getJMSMessageID(), CLASS_NAME, className);
        try {
            Class<?> clazz = Class.forName(className);
            JAXBContext context = JAXBContext.newInstance(clazz);
            return context.createUnmarshaller().unmarshal(new StringReader(payload));
        } catch (JAXBException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

Messages of different type (OrderTransaction or Person) where send every 5 seconds to the queue:

@Scheduled(fixedDelay = 5000)
public void sendMessage() {
    if ((int)(Math.random()*2) == 0) {
        jmsTemplate.convertAndSend("DummyQueue", new OrderTransaction(new Person("Mark", "Smith"), new Person("Tom", "Smith"), BigDecimal.TEN));
    }
    else {
        jmsTemplate.convertAndSend("DummyQueue", new Person("Mark", "Rutte"));
    }
}

Two listeners were defined:

@JmsListener(destination = "DummyQueue", containerFactory = "myFactory")
public void receiveOrderTransactionMessage(OrderTransaction transaction) {
    log.info("Received {}", transaction);
}

@JmsListener(destination = "DummyQueue", containerFactory = "myFactory")
public void receivePersonMessage(Person person) {
    log.info("Received {}", person);
}

When I place breakpoints in the converter I see everything works fine but sometimes (not always) I get the following exception:

org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method could not be invoked with incoming message
Endpoint handler details:
Method [public void nl.smith.springmdb.configuration.MyListener.**receiveOrderTransactionMessage**(nl.smith.springmdb.domain.**OrderTransaction**)]
Bean [nl.smith.springmdb.configuration.MyListener@790fe82a]
; nested exception is org.springframework.messaging.converter.MessageConversionException: Cannot convert from [nl.smith.springmdb.domain.**Person**] to [nl.smith.springmdb.domain.**OrderTransaction**] for org.springframework.jms

It seems that after the conversion Spring invokes the wrong method. I am complete in the dark why this happens. Can somebody clarify what is happening?

0 Answers
Related