Annotated Java Beans for Marshalling

This provides an example of an annotated Java bean that will reliably marshal as either JSON or XML.  The use of a java.util.Date object requires a custom marshal process to render the date consistently in both JSON and XML.  In this case, the Date object is rendered as a unix epoch timestamp.  Which on most *nix systems is the number of milliseconds since 1/1/1970 at UTC.

Annotated Java Bean

The following Java object can be ‘marshalled’ with either the FasterXML Jackson library (for json) or the JAXB library (for xml).  Note that the Jackson library can use many of the JAXB annotations, so for instance, there is no need to repeat the attribute naming (the XmlElement for instance) with its Jackson equivalent unless the attribute names are different between the two formats (as is the case with list naming).


package org.t35;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.mule.marshalling.xml.adapter.EpochMillisAdapter;

import com.fasterxml.jackson.annotation.JsonProperty;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class RegistrationDTO implements Cloneable {
	@XmlElement(required = true)
	private static String registrationCode = UUID.randomUUID().toString();
	
	@XmlElement(required = false)
	private String firstName;
	
	@XmlElement(required = false)
	private String middleName;
	
	@XmlElement(required = false)
	private String lastName;
	
	@XmlElement(required = true)
	private String email;
	
	@XmlElement(required = false)
	private String phone;
	
	@XmlElement(required = false)
	private String street;
	
	@XmlElement(required = false)
	private String city;
	
	@XmlElement(required = false)
	private String provinceOrState;
	
	@XmlElement(required = false)
	private String country;
	
	@XmlElement(required = false)
	private String postalCode;
	
	@XmlElement(required = false)
	private double registrationCost;
	
	@XmlElement(required = false)
	@XmlJavaTypeAdapter(EpochMillisAdapter.class)
	private Date registrationDate;
	
	@XmlElement(required = false)
	@XmlJavaTypeAdapter(EpochMillisAdapter.class)
	private Date attendenceDate;
	
	@JsonProperty("referenceCodes")
	@XmlElement(required = false, name = "referenceCode")
	private List referenceCodes = new ArrayList();
	
	@JsonProperty("items")
	@XmlElement(required = false, name = "item")
	private List items = new ArrayList();

	
	//----------------------------------------------------------//

	@Override
	public RegistrationDTO clone() throws CloneNotSupportedException {
		return (RegistrationDTO) super.clone();
	}
	
	@Override
	public String toString() {
		DecimalFormat df = new DecimalFormat();
		df.setMinimumFractionDigits(2);
		df.setMaximumFractionDigits(2);
		df.setMinimumIntegerDigits(1);
		df.setMaximumIntegerDigits(10);
		df.setRoundingMode(RoundingMode.DOWN);
		
		StringBuffer sb = new StringBuffer();
		sb.append(registrationCode).append("|");
		sb.append(firstName).append("|");
		sb.append(middleName).append("|");
		sb.append(lastName).append("|");
		sb.append(email).append("|");
		sb.append(phone).append("|");
		sb.append(street).append("|");
		sb.append(city).append("|");
		sb.append(provinceOrState).append("|");
		sb.append(country).append("|");
		sb.append(postalCode).append("|");
		sb.append(df.format(registrationCost)).append("|");
		sb.append(registrationDate.toString()).append("|");
		sb.append(attendenceDate.toString()).append("|");
		sb.append("References(").append(referenceCodes.size()).append(") ");
		for (String ref:referenceCodes) {
			sb.append(ref).append("|");
		}
		sb.append("items(").append(items.size()).append(") ");
		for (RegistrationItemDTO item: items) {
			sb.append(item.toString()).append("|");
		}
		return sb.toString();
	}

	public static String getRegistrationCode() {
		return registrationCode;
	}

	public static void setRegistrationCode(String registrationCode) {
		RegistrationDTO.registrationCode = registrationCode;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getMiddleName() {
		return middleName;
	}

	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getProvinceOrState() {
		return provinceOrState;
	}

	public void setProvinceOrState(String provinceOrState) {
		this.provinceOrState = provinceOrState;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getPostalCode() {
		return postalCode;
	}

	public void setPostalCode(String postalCode) {
		this.postalCode = postalCode;
	}

	public Double getRegistrationCost() {
		return registrationCost;
	}

	public void setRegistrationCost(Double registrationCost) {
		this.registrationCost = registrationCost;
	}

	public Date RegistrationDate() {
		return registrationDate;
	}

	public void setRegistrationDate(Date registrationDate) {
		this.registrationDate = registrationDate;
	}

	public Date getAttendenceDate() {
		return attendenceDate;
	}

	public void setAttendenceDate(Date attendenceDate) {
		this.attendenceDate = attendenceDate;
	}

	public List getReferenceCodes() {
		return referenceCodes;
	}

	public void setReferenceCodes(List referenceCodes) {
		this.referenceCodes = referenceCodes;
	}

	public List getItems() {
		return items;
	}

	public void setItems(List items) {
		this.items = items;
	}

}

XmlJavaAdapter

The XmlJavaAdapter used for the Date rendering the Java bean is shown below. Since Jackson is already annotating the date as a unix epoch date, marshalling instructions are only required for the JAXB serialization. Note that java.util.Date values are affected by physical machine configurations, so using the Date object does not guarantee that the serialized data is accurate. Check your implementations and deployments to verify that your machine’s are correctly producing unix epoch timestamps.


package org.mule.marshalling.xml.adapter;

import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class EpochMillisAdapter extends XmlAdapter {

	@Override
	public String marshal(Date v) throws Exception {
		return Long.valueOf(v.getTime()).toString();
	}

	@Override
	public Date unmarshal(String v) throws Exception {
		return new Date(Long.parseLong(v));
	}

}

Eclipse Maven Dependencies

If this code is built in Eclipse instead of Anypoint (Mule) Studio, the following maven dependencies are required. Once built, the jar file can be dropped into the lib folder of the Mule project directory (and the jar file added to the build path).


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.t35</groupId>
    <artifactId>mule-marshalling-interceptor</artifactId>
    <version>0.0.1</version>
    <name>Marshalling Interceptor for Mule ESB</name>
    <description>Marshalling Interceptor for Mule ESB</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <mule.version>3.4.1</mule.version>
        <jdkName>JavaSE-1.6</jdkName>
        <jdk.version>1.6</jdk.version>
        <junit.version>4.9</junit.version>
    </properties>

    <repositories>
        <repository>
            <id>Central</id>
            <name>Central</name>
            <url>http://repo1.maven.org/maven2/</url>
            <layout>default</layout>
        </repository>
        <repository>
            <id>mulesoft-releases</id>
            <name>MuleSoft Releases Repository</name>
            <url>http://repository.mulesoft.org/releases/</url>
            <layout>default</layout>
        </repository>
        <repository>
            <id>mulesoft-snapshots</id>
            <name>MuleSoft Snapshots Repository</name>
            <url>http://repository.mulesoft.org/snapshots/</url>
            <layout>default</layout>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>mulesoft-release</id>
            <name>mulesoft release repository</name>
            <layout>default</layout>
            <url>http://repository.mulesoft.org/releases/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                    <encoding>ISO-8859-1</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2.1</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>project</descriptorRef>
                    </descriptorRefs>
                    <finalName>mule-marshalling-interceptors</finalName>
                </configuration>
            </plugin>
            <!-- plugin> <groupId>org.jsonschema2pojo</groupId> <artifactId>jsonschema2pojo-maven-plugin</artifactId> 
                <version>0.4.2</version> <configuration> <sourceDirectory>${basedir}/src/main/api/schemas</sourceDirectory> 
                <targetPackage>com.example.types</targetPackage> </configuration> <executions> 
                <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> 
                </plugin -->
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.mule</groupId>
            <artifactId>mule-core</artifactId>
            <version>${mule.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>
</project>
Advertisement