Saturday, March 2, 2013

Spring JMS Message Converter

Spring’s JMS template helps us to convert JMS messages to and from Java objects using a message converter. By default, the JMS template uses SimpleMessageConverter for converting TextMessage to/from a string etc. Spring's JMS provides an interface MessageConverter  to create a custom message converter by implementing  fromMessage() and toMessage() methods.
Setup ActiveMQ : Refer to the previous post (JMS using ActiveMQ) for ActiveMQ setup
 In our previous post(JMS using Spring and ActiveMQ), we saw how to create a simple application using Spring's JMS API and Apache ActiveMQ. In this post, we are going to learn about user defined message converter and its usage.
              We need to include Apache ActiveMQ library in our classpath . download


In our previous post, we saw how to send message and consume it from destination. We also witnessed that we were converting the MessageObject into MapMessage for sending and MessageObject from MapMessage while consuming as:
MapMessage message = session.createMapMessage();
message.setString("mailId", messageObj.getMailId());
message.setString("message", messageObj.getMessage());

This is our Plain old java class which will serve as our message Object. MessageObject.java
package com.sarf.data; 

public class MessageObject {
  private String mailId;
  private String message;
    
 public MessageObject(){}; 
 public MessageObject(String mailId, String message) {
  super();
  this.mailId = mailId;
  this.message = message;
 }
 public String getMailId() {
  return mailId;
 }
 public void setMailId(String mailId) {
  this.mailId = mailId;
 }
 public String getMessage() {
  return message;
 }
 public void setMessage(String message) {
  this.message = message;
 }
}



Create Custom Message Converter

Step 1 : We are going to write our customer message converter namely MyMessageConverter.java. This class will implement MessageConverter interface and provide implementation for methods  fromMessage() and toMessage( ). Method fromMessage() is responsible for converting a JMS Message to User Obect and method toMessage() is responsible for converting a User Object to JMS Message as shown below ;

MyMessageConverter.java
package com.sarf.util;

import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;

import org.springframework.jms.support.converter
 .MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter;
import com.sarf.data.MessageObject;

public class MyMessageConverter implements MessageConverter{
 public Object fromMessage(Message message) 
  throws JMSException,MessageConversionException {
  MapMessage mapMessage = (MapMessage) message;
  MessageObject messageObject = new MessageObject();
  messageObject.setMailId(mapMessage.getString("mailId"));
  messageObject.setMessage(mapMessage.getString("message"));
  return messageObject;
 }

 public Message toMessage(Object object, Session session) 
  throws JMSException,MessageConversionException {
  MessageObject messageObject = (MessageObject) object;
  MapMessage message = session.createMapMessage();
  message.setString("mailId", messageObject.getMailId());
  message.setString("message", messageObject.getMessage());
  return message;
  } 
}
Step 2 : We will create a bean for custom message converter and inject it into JMS Template bean as When we set custom message converter in JMS template explicitly, it overrides the default SimpleMessageConverter.


The full version of appContext.xml will look like : appContext.xml

After creating and configuring custom message converter, we can call the JMS template’s convertAndSend() and receiveAndConvert() methods to send and receive MessageObjecct objects in our MessageProducerBean.java and MessageConsumerBean.java as defined below:

Our producer and consumer classes are extending JmsGatewaySupport to retrieve a JMS template. We can get JMS Template using getJmsTemplate() method. 

MessageProducerBean.java
package com.sarf.jms;

import org.springframework.jms.core.support.JmsGatewaySupport;
import com.sarf.data.MessageObject;
public class MessageProducerBean extends JmsGatewaySupport{
 public void sendMessage(final MessageObject mail) { 
  getJmsTemplate().convertAndSend(mail);
 }
}

MessageConsumerBean.java
package com.sarf.jms;

import org.springframework.jms.core.support.JmsGatewaySupport;
import com.sarf.data.MessageObject;

public class MessageConsumerBean extends JmsGatewaySupport{
 public MessageObject receiveMessage() {
   return (MessageObject) getJmsTemplate().receiveAndConvert();
 }
}



We will write plain main method  in Producer class to send Message to a Queue and consume it using Consumer class.

ProducerTest
package com.sarf.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sarf.data.MessageObject;
import com.sarf.jms.MessageProducerBean;

public class ProducerTest {   
 public static void main(String[] args) {
   ApplicationContext context =
     new ClassPathXmlApplicationContext("appContext.xml");
   MessageProducerBean mp = 
    (MessageProducerBean) context.getBean("producer");
   mp.sendMessage(new MessageObject("34", "Test Message"));
   } 
}

ConsumerTest.java
package com.sarf.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sarf.data.MessageObject;
import com.sarf.jms.MessageConsumerBean;

public class ConsumerTest {
 public static void main(String[] args) {
   ApplicationContext context =
    new ClassPathXmlApplicationContext("appContext.xml");
   MessageConsumerBean mc = 
    (MessageConsumerBean) context.getBean("consumer");
   MessageObject mail = mc.receiveMessage();
   System.out.println("Mail from #" + mail.getMailId() + " received");
   }
}
Check JMS Post: