DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Spring Boot Centralized Logging with Graylog
  • How to Convert XLS to XLSX in Java
  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux

Trending

  • A Complete Guide to Modern AI Developer Tools
  • Start Coding With Google Cloud Workstations
  • Is Agile Right for Every Project? When To Use It and When To Avoid It
  • Automatic Code Transformation With OpenRewrite
  1. DZone
  2. Coding
  3. Frameworks
  4. Sending Beans as XML with JmsTemplate

Sending Beans as XML with JmsTemplate

By 
Gordon Dickens user avatar
Gordon Dickens
·
Feb. 08, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
17.5K Views

Join the DZone community and get the full member experience.

Join For Free

We often want to send XML via web services. We may already have the schema or annotated JAXB2 classes configured in our application. What if we want to send the same format via JMS? By default Spring JMS is configured to send & receive objects serialized. How can we switch to using JAXB2 (or any other OXM marshaling strategy)?


The following example assumes we are going from annotations first instead of from XML Schema.

Quick Overview

  1. Annotate Bean with JAXB2
  2. Configure OXM Converter
  3. Integration Test
  4. Visualize Results
  5. Logging Configuration
  6. Maven Configuration

1. Annotate Bean with JAXB2

  • Use JAXB2 annotations for our bean
package com.gordondickens.jmswithoxm;

import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "account")
@XmlAccessorType(XmlAccessType.FIELD)
public class Account {
@XmlElement(required = true)
private String name;

@XmlElement
private String description;

@XmlElement
private BigDecimal balance;

public String getName() {
return name;
}

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

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public BigDecimal getBalance() {
return balance;
}

public void setBalance(BigDecimal balance) {
this.balance = balance;
}

@Override
public String toString() {
return "Account [name=" + name + ", description=" + description
+ ", balance=" + balance + "]";
}
}

 2. Configure OXM Converter

  • Define our Marshalers – We see <oxm:jaxb2-marshaller ...> defines JAXB2 as our marshaller for the Account class
  • Register our MarshallingMessageConverter – We register the MarshallingMessageConverter to use the JAXB2 marshaller for both inbound and outbound data
  • Register our Converter – In the JmsTemplate, we register our oxmMessageConverter as the messageConverter. This replaces the default SimpleMessageConverter which will relies on Serialization
  • Notice the ActiveMQ namespace?

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<amq:broker persistent="false" useJmx="true">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:61616" />
</amq:transportConnectors>
</amq:broker>

<amq:connectionFactory brokerURL="vm://localhost" id="jmsFactory" />

<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory" />
<property name="defaultDestination" ref="oxmTestQueue" />
<property name="messageConverter" ref="oxmMessageConverter" />
</bean>

<amq:queue id="oxmTestQueue" physicalName="oxm.test.queue" />

<bean id="oxmMessageConverter"
class="org.springframework.jms.support.converter.MarshallingMessageConverter">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
</bean>

<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="com.gordondickens.jmswithoxm.Account" />
</oxm:jaxb2-marshaller>
</beans>

 

3. Integration Test

  • Populate the Account bean
  • Calls convertAndSend on the JmsTemplate to marshal & send the Account
  • Includes a postProcessor callback to log the XML data
  • Calls receiveAndConvert on the JmsTemplate to get & unmarshal the Account
  • Asserts end state
?
package com.gordondickens.jmswithoxm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.math.BigDecimal;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessagePostProcessor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JmsWithOxmTest {
private static final Logger logger = LoggerFactory
.getLogger(JunitWithOxmTest.class);
private static final String TEST_DEST = "oxmTestQueue";

@Autowired
JmsTemplate jmsTemplate;

@Test
public void testSendingMessage() {
Account account = generateTestMessage();
jmsTemplate.convertAndSend(TEST_DEST, account,
new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message)
throws JMSException {
if (message instanceof BytesMessage) {
BytesMessage messageBody = (BytesMessage) message;
// message is in write mode, close & reset to start
// of byte stream
messageBody.reset();

Long length = messageBody.getBodyLength();
logger.debug("***** MESSAGE LENGTH is {} bytes",
length);
byte[] byteMyMessage = new byte[length.intValue()];
int red = messageBody.readBytes(byteMyMessage);
logger.debug(
"***** SENDING MESSAGE - \n<!-- MSG START -->\n{}\n<!-- MSG END -->",
new String(byteMyMessage));
}
return message;
}
});
Account account2 = (Account) jmsTemplate.receiveAndConvert(TEST_DEST);
assertNotNull("Account MUST return from JMS", account2);
assertEquals("Name MUST match", account.getName(), account2.getName());
assertEquals("Description MUST match", account.getDescription(),
account2.getDescription());
assertEquals("Balance MUST match", account.getBalance(),
account2.getBalance());
}

private Account generateTestMessage() {
Account account = new Account();
account.setBalance(new BigDecimal(12345.67));
account.setDescription("A no account varmint");
account.setName("Waskally Wabbit");
logger.debug("Generated Test Message: " + account.toString());
return account;
}
}

 4. Visualizing Results

  • Run: mvn clean test
  • See Account XML between the block <!-- MSG START --> & <!--MSG END -->
  • Output has been Formatted for clarity
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.gordondickens.jmswithoxm.JmsWithOxmTest

INFO o.s.o.j.Jaxb2Marshaller - Creating JAXBContext
with classes to be bound [class com.gordondickens.jmswithoxm.Account]

DEBUG c.g.j.JmsWithOxmTest - Generated Test Message:
Account [name=Waskally Wabbit, description=A no account
varmint, balance=12345.670000000000072759576141834259033203125]

DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session:
ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:1:1,started=false}

DEBUG c.g.j.JmsWithOxmTest - ***** MESSAGE LENGTH is 213 bytes

DEBUG c.g.j.JmsWithOxmTest - ***** SENDING MESSAGE -
<!-- MSG START -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<account>
<name>Waskally Wabbit</name>
<description>A no account varmint</description>
<balance>12345.670000000000072759576141834259033203125</balance>
</account>
<!-- MSG END -->

DEBUG o.s.j.c.JmsTemplate - Sending created message:
ActiveMQBytesMessage {commandId = 0, responseRequired = false, messageId = null, originalDestination = null, originalTransactionId = null, producerId = null, destination = null, transactionId = null, expiration = 0, timestamp = 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = false, type = null, priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@b364dcb, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = true, droppable = false} ActiveMQBytesMessage{ bytesOut = null, dataOut = null, dataIn = java.io.DataInputStream@1a2d502d }

DEBUG o.s.j.c.JmsTemplate - Executing callback on JMS Session:
ActiveMQSession {id=ID:Technophiliac-61135-1296856347600-2:2:1,started=true}

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.276 sec

 

5. Logging Configuration

  • Logback is very similar to Log4J
  • Logback patterns use Log4J characters also
  • See: Logback Pattern Layout Documentation
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%-5level %logger{5} - %msg%n</pattern>
</encoder>
</appender>

<logger name="com.gordondickens" level="DEBUG" />
<logger name="org.springframework.jms" level="DEBUG" />
<logger name="org.springframework.oxm" level="DEBUG" />
<!--<logger name="org.apache.activemq" level="DEBUG"/> -->

<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>

 6. Maven Configuration

  • Using Logback to support Log4J, SLF4J, Apache (JCL) & Java Util Logging
  • Included IDE builders for STS/Eclipse & IntelliJ IDEA
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gordondickens.jmswithoxm</groupId>
<artifactId>spring-jms-oxm</artifactId>
<version>1.0.0.CI-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JMS to OXM Spring</name>
<url>http://gordondickens.com</url>
<description>Sample JMS with OXM Message Conversion</description>
<developers>
<developer>
<id>gordon.dickens</id>
<name>Gordon Dickens</name>
<email>gordondickens@gmail.com</email>
<roles>
<role>Author</role>
</roles>
<organization>http://www.gordondickens.com</organization>
</developer>
</developers>

<properties>
<spring.version>3.0.5.RELEASE</spring.version>
<junit.version>4.8.1</junit.version>
<jms.version>1.1.1</jms.version>
<slf4j.version>1.6.1</slf4j.version>
<activemq.version>5.4.2</activemq.version>
<logback.version>0.9.27</logback.version>
<log4j.version>1.2.16</log4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.test.failure.ignore>false</maven.test.failure.ignore>
</properties>
<profiles>
<profile>
<id>quick</id>
<properties>
<maven.test.failure.ignore>true</maven.test.failure.ignore>
</properties>
</profile>
</profiles>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>${activemq.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.7</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jms_1.1_spec</artifactId>
<version>${jms.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.8</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>2.0</wtpversion>
<additionalBuildcommands>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
</buildCommand>
</additionalBuildcommands>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-idea-plugin</artifactId>
<version>2.2</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<dependenciesAsLibraries>true</dependenciesAsLibraries>
</configuration>
</plugin>
</plugins>
</build>
</project>

 6. Getting the code

  • Code is in my Git Repo:
    https://github.com/gordonad/core-spring-demos/tree/master/demos/JmsOxmDemo

 Further Reading

  • Spring Reference for JMS – Section 21.3.1 Using Message Converters
  • Core Spring Training – Where I teach JMS with Spring
  • Enterprise Integration with Spring Training – Where I teach JMS with Spring

From http://gordondickens.com/wordpress/2011/02/07/sending-beans-as-xml-with-jmstemplate/

XML Spring Framework

Opinions expressed by DZone contributors are their own.

Related

  • Spring Boot Centralized Logging with Graylog
  • How to Convert XLS to XLSX in Java
  • How Spring and Hibernate Simplify Web and Database Management
  • Functional Endpoints: Alternative to Controllers in WebFlux

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: