Spring JMS Message Converter Example

5 minute read

spring jms message converter

Today you’re going to see how to implement a MessageConverter using Spring JMS.

The best part?

It’s really easy to do.

So let’s get down to business

If you want to learn more about Spring JMS - head on over to the Spring JMS tutorials page.

1. What is a Message Converter?

A MessageConverter specifies how to convert between Java objects and JMS messages.

Spring JMS comes with a number of implementations that are ready to use. By default, the SimpleMessageConverter is used by the framework. It is able to handle TextMessages, BytesMessages, MapMessages, and ObjectMessages.

Let’s build an example to show how you can use a message converter with Spring JMS. We start from a previous Spring with JMS example. We will adapt it so that we can send a Person object that gets converted to/from JSON.

Note that Spring JMS ships with a MappingJackson2MessageConverter that converts messages to and from JSON. We will not use it and create our own custom implementation instead.

2. General Project Overview

We will use the following tools/frameworks:

  • Spring JMS 5.1
  • Spring Boot 2.1
  • ActiveMQ 5.14
  • Maven 3.5

Our project has the following directory structure:

spring jms message converter maven project

3. Create a Custom JSON Message Converter

First, we define a simple Person class that contains a name and age. It is a simple POJO with the needed constructors and getters/setters.

package com.codenotfound.jms;

public class Person {

  private String name;

  private int age;

  public Person() {
    super();
  }

  public Person(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  @Override
  public String toString() {
    return "person[name=" + name + ", age=" + age + "]";
  }
}

Next, create a PersonMessageConverter class that implements the MessageConverter interface.

You need to implement two methods: toMessage() and fromMessage(). These specify how the conversion between the Person object and JMS message is done.

In the toMessage() method we create a TextMessage. As payload, we set the JSON String representation of a Person.

The fromMessage() method converts the JSON String from a JMS message into a Person.

The conversion between a Java object and JSON is done using a Jackson ObjectMapper.

Annotate the class with @Component so that Spring registers the class as a Bean. When Spring Boot detects this class it is auto-configured on both the JmsTemplate and DefaultJmsListenerContainerFactory.

You can also set the MessageConverter on the JmsTemplate and MessageListenerContainer using setMessageConverter(). But this means you need to create these Beans as we saw in a previous Spring JMS Example.

package com.codenotfound.jms;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Component
public class PersonMessageConverter implements MessageConverter {

  private static final Logger LOGGER =
      LoggerFactory.getLogger(PersonMessageConverter.class);

  ObjectMapper mapper;

  public PersonMessageConverter() {
    mapper = new ObjectMapper();
  }

  @Override
  public Message toMessage(Object object, Session session)
      throws JMSException {
    Person person = (Person) object;
    String payload = null;
    try {
      payload = mapper.writeValueAsString(person);
      LOGGER.info("outbound json='{}'", payload);
    } catch (JsonProcessingException e) {
      LOGGER.error("error converting form person", e);
    }

    TextMessage message = session.createTextMessage();
    message.setText(payload);

    return message;
  }

  @Override
  public Object fromMessage(Message message) throws JMSException {
    TextMessage textMessage = (TextMessage) message;
    String payload = textMessage.getText();
    LOGGER.info("inbound json='{}'", payload);

    Person person = null;
    try {
      person = mapper.readValue(payload, Person.class);
    } catch (Exception e) {
      LOGGER.error("error converting to person", e);
    }

    return person;
  }
}

To wrap up, make sure to also change the Sender and Receiver so that a Person object is sent/received.

4. Test the JMS Message Converter

To test the message converter, create a Person and send it to the converter.q queue.

package com.codenotfound.jms;

import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class SpringJmsApplicationTest {

  @Autowired
  private Sender sender;

  @Autowired
  private Receiver receiver;

  @Test
  public void testReceive() throws Exception {
    Person person = new Person("John Doe", 20);
    sender.send("converter.q", person);

    receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
    assertThat(receiver.getLatch().getCount()).isEqualTo(0);
  }
}

Open a command prompt in the root directory of the project. Execute following Maven command:

mvn test

The log output shows that the message is converted to/from a JSON representation.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

2018-12-11 11:09:24.142  INFO 13988 --- [           main] c.c.jms.SpringJmsApplicationTest         : Starting SpringJmsApplicationTest on DESKTOP-2RB3C1U with PID 13988 (started by Codenotfound in C:\Users\Codenotfound\repos\spring-jms\spring-jms-message-converter)
2018-12-11 11:09:24.142  INFO 13988 --- [           main] c.c.jms.SpringJmsApplicationTest         : No active profile set, falling back to default profiles: default
2018-12-11 11:09:25.408  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Using Persistence Adapter: MemoryPersistenceAdapter
2018-12-11 11:09:25.455  INFO 13988 --- [  JMX connector] o.a.a.broker.jmx.ManagementContext       : JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
2018-12-11 11:09:25.580  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Apache ActiveMQ 5.15.8 (localhost, ID:DESKTOP-2RB3C1U-65207-1544522965439-0:1) is starting
2018-12-11 11:09:25.595  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Apache ActiveMQ 5.15.8 (localhost, ID:DESKTOP-2RB3C1U-65207-1544522965439-0:1) started
2018-12-11 11:09:25.595  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : For help or more information please see: http://activemq.apache.org
2018-12-11 11:09:25.627  INFO 13988 --- [           main] o.a.activemq.broker.TransportConnector   : Connector vm://localhost started
2018-12-11 11:09:25.674  INFO 13988 --- [           main] c.c.jms.SpringJmsApplicationTest         : Started SpringJmsApplicationTest in 1.891 seconds (JVM running for 2.876)
2018-12-11 11:09:25.845  INFO 13988 --- [           main] com.codenotfound.jms.Sender              : sending person='person[name=John Doe, age=20]' to destination='converter.q'
2018-12-11 11:09:25.892  INFO 13988 --- [           main] c.c.jms.PersonMessageConverter           : outbound json='{"name":"John Doe","age":20}'
2018-12-11 11:09:25.908  INFO 13988 --- [enerContainer-1] c.c.jms.PersonMessageConverter           : inbound json='{"name":"John Doe","age":20}'
2018-12-11 11:09:25.939  INFO 13988 --- [enerContainer-1] com.codenotfound.jms.Receiver            : received person='person[name=John Doe, age=20]'
2018-12-11 11:09:26.939  INFO 13988 --- [           main] o.a.activemq.broker.TransportConnector   : Connector vm://localhost stopped
2018-12-11 11:09:26.939  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Apache ActiveMQ 5.15.8 (localhost, ID:DESKTOP-2RB3C1U-65207-1544522965439-0:1) is shutting down
2018-12-11 11:09:26.955  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Apache ActiveMQ 5.15.8 (localhost, ID:DESKTOP-2RB3C1U-65207-1544522965439-0:1) uptime 1.703 seconds
2018-12-11 11:09:26.955  INFO 13988 --- [           main] o.apache.activemq.broker.BrokerService   : Apache ActiveMQ 5.15.8 (localhost, ID:DESKTOP-2RB3C1U-65207-1544522965439-0:1) is shutdown
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.843 s - in com.codenotfound.jms.SpringJmsApplicationTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.004 s
[INFO] Finished at: 2018-12-11T11:09:27+01:00
[INFO] ------------------------------------------------------------------------

github mark If you would like to run the above code sample you can get the full source code here.

In this tutorial, you learned how to create a custom Spring JMS message converter.

Let me know if you found this example useful.

Thanks!

Leave a comment