Skip to content

December 19, 2010

1

Java Bean mapping with Dozer

Introduction

This article describes how to use Dozer to copy data between different Java class types. Dozer is a mapping framework that recursively copies data from one object to another with typical use cases such as converting between domain objects and data transfer objects (DTOs) or mapping classes from an external library to your application objects.

Add dependency references to your project

The Dozer dependencies can be referenced within a Maven project POM file as follows:

<dependency>
	<groupId>net.sf.dozer</groupId>
  	<artifactId>dozer</artifactId>
  	<version>5.3.1</version>
</dependency>
<dependency>
	<groupId>org.apache.xmlbeans</groupId>
	<artifactId>xmlbeans</artifactId>
	<version>2.4.0</version>
	<scope>runtime</scope>
</dependency>

Specify source classes

In this scenario the source classes contain collection objects that must also be mapped. These collection objects are non-primitive data types requiring that sub-mappings are also specified.

The containing object Basket for the source object.

package net.comdynamics.myapp;

import java.util.ArrayList;
import java.util.List;

public class Basket {

	private String customerName;
	private List<Product> products;

	public Basket() {
		products = new ArrayList<Product>();
	}

	public Basket(String customerName, List<Product> products) {
		this.customerName = customerName;
		this.products = products;
	}

	public String getCustomerName() {
		return customerName;
	}

	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}

	public List<Product> getProducts() {
		return products;
	}

	public void setProducts(List<Product> products) {
		this.products = products;
	}
}

The collection object Product for the source object.

package net.comdynamics.myapp;

import java.math.BigDecimal;

public class Product {

	private String name;
	private String description;
	private BigDecimal price;

	public Product() {
	}

	public Product(String name, String description, BigDecimal price) {
		this.name = name;
		this.description = description;
		this.price = price;
	}

	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 getPrice() {
		return price;
	}

	public void setPrice(BigDecimal price) {
		this.price = price;
	}

}

Specify target classes

The target classes should contain fields that you need to copy data into as these will be mapped in the Dozer configuration file.

The containing object BasketCase for the target object.

package net.comdynamics.myapp;

import java.util.ArrayList;
import java.util.List;

public class BasketCase {

	private String customerNameOutput;
	private List<ProductOffering> productListOutput;

	public BasketCase() {
		productListOutput = new ArrayList<ProductOffering>();
	}

	public BasketCase(String customerName, List<ProductOffering> products) {
		this.customerNameOutput = customerName;
		this.productListOutput = products;
	}

	public String getCustomerNameOutput() {
		return customerNameOutput;
	}

	public void setCustomerNameOutput(String customerNameOutput) {
		this.customerNameOutput = customerNameOutput;
	}

	public List<ProductOffering> getProductListOutput() {
		return productListOutput;
	}

	public void setProductListOutput(List<ProductOffering> productListOutput) {
		this.productListOutput = productListOutput;
	}

}

The collection object ProductOffering for the target object.

package net.comdynamics.myapp;

import java.math.BigDecimal;

public class ProductOffering {

	private String nameOutput;
	private String descriptionOutput;
	private BigDecimal priceOnline;

	public ProductOffering() {
	}

	public ProductOffering(String nameOutput, String descriptionOutput,
			BigDecimal priceOnline) {
		this.nameOutput = nameOutput;
		this.descriptionOutput = descriptionOutput;
		this.priceOnline = priceOnline;
	}

	public String getNameOutput() {
		return nameOutput;
	}

	public void setNameOutput(String nameOutput) {
		this.nameOutput = nameOutput;
	}

	public String getDescriptionOutput() {
		return descriptionOutput;
	}

	public void setDescriptionOutput(String descriptionOutput) {
		this.descriptionOutput = descriptionOutput;
	}

	public BigDecimal getPriceOnline() {
		return priceOnline;
	}

	public void setPriceOnline(BigDecimal priceOnline) {
		this.priceOnline = priceOnline;
	}

}

Create Dozer XML mapping file

Create an XML file called dozerBeanMapping.xml and ensure it is accessible from your classpath at runtime. This file should include mapping for the containing Basket object and the collection Product object. When mapping the collection object you should specify the fully-qualified class name for the destination object using the b-hint element.


<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dozer.sourceforge.net

http://dozer.sourceforge.net/schema/beanmapping.xsd">

	<mapping>
		<class-a>net.comdynamics.myapp.Basket</class-a>
		<class-b>net.comdynamics.myapp.BasketCase</class-b>
		<field>
			<a>customerName</a>
			<b>customerNameOutput</b>
		</field>
		<field>
		  	<a>products</a>
  			<b>productListOuput</b>
		  	<b-hint>net.comdynamics.myapp.ProductOffering</b-hint>
  		</field>
	</mapping>

	<mapping>
		<class-a>net.comdynamics.myapp.Product</class-a>
		<class-b>net.comdynamics.myapp.ProductOffering</class-b>
		<field>
			<a>name</a>
			<b>nameOutput</b>
		</field>
		<field>
			<a>description</a>
			<b>descriptionOutput</b>
		</field>
		<field>
			<a>price</a>
			<b>priceOnline</b>
		</field>
	</mapping>

</mappings>

Converting object types

Using the Dozer singleton mapper instance it is then possible to convert from the source object to the destination object. Using the above example classes:

// Create instance of Basket
Basket sourceObject = new Basket();
// Object populated with some values...
// etc
// Get mapping instance and convert
Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
// Convert source to destination object
BasketCase destObject = mapper.map(sourceObject, BasketCase.class);

Spring Integration

If you need to load custom mapping files in your Spring application context, add an entry similar to the following whereby each mapping file is listed separately:

<bean id="mapper" class="org.dozer.DozerBeanMapper">
    <property name="mappingFiles">
        <list>
            <value>xml-bean-mappings.xml</value>			   
            <value>dto-bean-mappings.xml</value>
        </list>
    </property>
</bean>
Read more from Java
1 Comment
  1. Mick
    Jan 28 2011

    I’ve lost count of the number of times I’ve had to write assemblers to populate a DTO from domain objects. Dozer certainly looks like a elegant solution to this common requirement.

Comments are closed.