Dozer is a powerful library which can help us in avoiding lots of unnecessary code, while we want to copy data from one bean to another bean. It is mainly bean to bean mapper that recursively copies data from one java object to another java object – attribute by attribute.

We realize it’s full capability when We are dealing with deeply-nested complex java beans, which we are easily seen in large enterprise applications. To copy data from one such large bean to another similar bean can have hundreds of lines of code

Table of Contents

1. What is bean mapper and why it is important
2. Dozer Maven Dependency
3. Simple Bean Mapping Example
4. Dozer Mapping with XML Mapping File
5. Dozer Mapping with Annotations
6. Dozer Custom Converter Example
7. Dozer BeanMappingBuilder Example
8. Spring DozerBeanMapper example
9. Summary

1. What is bean mapper and why it is important

Now a days all enterprise projects are quite complex in nature and usually to accomplish certain business functionality, we need to call external systems, legacy components which requires transformations of different types of objects whose structure is more or less same, like domain Object to external Service request / external service response to domain objects and so on.

Now in real world scenario those request/response objects may contain high number of fields, so in order to copy data from one object to another object, if we need to write code manually for that, it will require lots of coding like destination.setXYZ(source.getXYZ()) which are repetitive in nature and error prone, in terms of missing fields, error in matching etc.

In those scenario, Bean mapper comes into picture and becomes very handy in copying values from one bean to another bean with some simple configurations and few lines of code. Today we will learn about Dozer bean mapper and will do demo on both spring and non-spring way.

2. Dozer maven dependency

To use dozer, we need to add below dependency in pom.xml of our maven project.

<dependency>
	<groupId>net.sf.dozer</groupId>
	<artifactId>dozer</artifactId>
	<version>5.5.1</version>
</dependency>

3. Dozer bean mapping example

We have two classes, ClassA and ClassB, with three fields. Field names are similar but their data type may not be same. Here Dozer will able to handle it automatically without anything special.

package com.example.howtodoinjava.dozer.simple;

public class ClassA {

	private String name;
	private String age;
	private String address;

	//Getters and Setters
}

package com.example.howtodoinjava.dozer.simple;

public class ClassB {

	private String name;
	private int age;
	private String address;

	//Getters and Setters
}

A simple dozer bean mapping example.

package com.example.howtodoinjava.dozer.simple;

import org.dozer.DozerBeanMapper;

public class SimpleExample 
{
	public static void main(String[] args) 
	{
		ClassA classA = new ClassA();
		classA.setAddress("India");
		classA.setName("Sajal");
		classA.setAge("50");

		ClassB classB = new DozerBeanMapper().map(classA, ClassB.class);
		System.out.println(classB);
	}
}

Program output.

Output: ClassB toString after applying Dozer transformation : ClassB [name=Sajal, age=50, address=India]

4. Dozer bean mapping with xml mapping

In this example, SourceObject contains a list of Student objects and few other fields. Similarly, DestinationObject also has a list of StudentVO object along with few other simple fields. We will use XML mapping file to map attributes of the SourceObject to DestinationObject.

package com.example.howtodoinjava.dozer.models;

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

public class SourceObject {

	private String name;
	private String address;
	List<Student> students;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

public class Student {

	String name;
	String batch;
	String address;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

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

public class DestinationObject {
	
	private String name;
	private String address;
	List<StudentVO> pupils;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

public class StudentVO {

	String name;
	String batchName;
	String homeAddress;

	//Getters and Setters
}

Bean mapping xml file is given below.

<?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>com.example.howtodoinjava.dozer.models.SourceObject</class-a>
        <class-b>com.example.howtodoinjava.dozer.models.DestinationObject</class-b>
        <field>
            <a>students</a>
            <b>pupils</b>
        </field>
    </mapping>

    <mapping>
        <class-a>com.example.howtodoinjava.dozer.models.Student</class-a>
        <class-b>com.example.howtodoinjava.dozer.models.StudentVO</class-b>
        <field>
            <a>batch</a>
            <b>batchName</b>
        </field>
        <field>
            <a>address</a>
            <b>homeAddress</b>
        </field>
    </mapping>

</mappings>

For detailed reference, you can follow the dozer user guide.

package com.example.howtodoinjava.dozer.demo.withoutspring;

import java.util.Arrays;

import org.dozer.DozerBeanMapper;

import com.example.howtodoinjava.dozer.models.DestinationObject;
import com.example.howtodoinjava.dozer.models.SourceObject;
import com.example.howtodoinjava.dozer.models.Student;

public class Demo {

	public static void main(String[] args) 
	{
		DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
		SourceObject sourceObject = new SourceObject();
		sourceObject.setName("Sajal");
		sourceObject.setAddress("India");

		sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));
		sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));
		sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));

		dozerBeanMapper.setMappingFiles(Arrays.asList("mappings\\student-mapper.xml"));
		DestinationObject destinationObject = dozerBeanMapper.map(sourceObject, DestinationObject.class);

		System.out.println(destinationObject);
	}
}

Program output.

DestinationObject [name=Sajal, address=India, pupils=[
 StudentVO [name=S1, batchName=C1, homeAddress=diffField1],
 StudentVO [name=S2, batchName=C2, homeAddress=diffField2], 
 StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]
]

5. Dozer bean mapping annotations – @Mapping

Dozer configuration can also be done @Mapping annotation provided by dozer. It can be put onto the mapped property itself thus reducing the amount of code.

Currently, @Mapping is the only annotation provided by dozer and it helps in very simple properties mappings. If you got anything complex, then go for XML mapping or custom converters.

In this example, I have modified classes used in XML mapping demo, to keep the approaches comparable.

package com.example.howtodoinjava.dozer.models;

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

public class SourceObject {

	private String name;
	private String address;

	@Mapping("pupils")
	List<Student> students;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

public class Student {

	String name;

	@Mapping("batchName")
	String batch;

	@Mapping("homeAddress")
	String address;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

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

public class DestinationObject {
	
	private String name;
	private String address;
	List<StudentVO> pupils;

	//Getters and Setters
}
package com.example.howtodoinjava.dozer.models;

public class StudentVO {

	String name;
	String batchName;
	String homeAddress;

	//Getters and Setters
}

Dozer @Mapping annotation example.

import org.dozer.DozerBeanMapper;

public class AnnotationExample {

	public static void main(String[] args) 
	{
		SourceObject sourceObject = new SourceObject();
		sourceObject.setName("Sajal");
		sourceObject.setAddress("India");

		sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));
		sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));
		sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));
		
		DestinationObject targetObj = new DozerBeanMapper().map(sourceObject, DestinationObject.class);
		System.out.println("DestinationObject : " + targetObj);
	}
}

Program output.

DestinationObject [name=Sajal, address=India, pupils=[
 StudentVO [name=S1, batchName=C1, homeAddress=diffField1],
 StudentVO [name=S2, batchName=C2, homeAddress=diffField2], 
 StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]
]

6. Dozer custom converters example

Till now we saw how Dozer can help us in copying field values from source to target object. However in real life scenario, we might require to add some logic before and after converting the values. I these cases Dozer provided custom converters comes into play. We can add any kind of some transformation logic in these converters.

In this example, while copying from source to destination, we want to convert the string value to UPPERCASE. Let’s see how we can achieve this.

package com.example.howtodoinjava.dozer.converters;

public class SourceObject {
	
	private String fullname;

	//Getters, Setters, Constrctors and toString Method
}
package com.example.howtodoinjava.dozer.converters;

public class DestinationObject {
	
	private String fullname;

	//Getters, Setters, Constrctors and toString Method
}

Any custom converter will have to extend DozerConverter with source and destination as parameters. Then we need to override convertFrom(source, destination) and convertTo(source, destination) methods to add logic for forward and backward conversions.

import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerConverter;

public class UpperCaseConverter extends DozerConverter<String, String> 
{
	public UpperCaseConverter() {
		super(String.class, String.class);
	}

	@Override
	public String convertFrom(String source, String destination) {
		if (source != null) {
			return StringUtils.upperCase(source);
		}
		return null;
	}

	@Override
	public String convertTo(String source, String destination) {
		//No Modification when copy backward
		return convertTo(source, destination);
	}
}

Now we need to register this converter in Dozer, we will do it in the mappings file as below. There are couple of variations here like we can register custom converter in the global declaration section or in Field section etc.

For details, please visit the official dozer documentation.

<?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>com.example.howtodoinjava.dozer.converters.SourceObject</class-a>
        <class-b>com.example.howtodoinjava.dozer.converters.DestinationObject</class-b>
        <field custom-converter="com.example.howtodoinjava.dozer.converters.UpperCaseConverter" custom-converter-param="fullname">
            <a>fullname</a>
            <b>fullname</b>
        </field>
    </mapping>
</mappings>

Now register the dozer bean mapper in spring as we have already seen in earlier section.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	
	<bean id="dozerBeanMapper" class="org.dozer.DozerBeanMapper">
		<property name="mappingFiles">
			<list>
				<value>custom-converter-mapping.xml</value>
			</list>
		</property>
	</bean>
	
</beans>

Dozer custom converter example program.

import org.dozer.DozerBeanMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CustomConverterTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {

		SourceObject sourceClassForConverters = new SourceObject("Lokesh Gupta");
		
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("custom-converter-spring-beans.xml");
		DozerBeanMapper beanMapper = (DozerBeanMapper) applicationContext.getBean("dozerBeanMapper");
		
		DestinationObject destinationClassForConverters = beanMapper.map(sourceClassForConverters, DestinationObject.class);
		
		System.out.println(destinationClassForConverters);
	}
}

Program output.

DestinationObject [fullname=LOKESH GUPTA]

7. Dozer BeanMappingBuilder Example

Till now, we learned to configure Dozer using xml and annotation configurations. Now we ill learn how we can declare Dozer mapping programatically using BeanMappingBuilder class.

In this example, we have created two classes SourceObject and DestinationObject. Both have single field date, only their data type is different.

public class DestinationObject {
	
	String date;
}
import java.util.Date;

public class DestinationObject {
	
	Date date;
}

Java program to show dozer BeanMappingBuilder example.

package com.example.howtodoinjava.dozer.api;

import org.dozer.DozerBeanMapper;
import org.dozer.loader.api.BeanMappingBuilder;
import org.dozer.loader.api.TypeMappingOptions;

public class BeanMappingBuilderExample {

	public static void main(String[] args) {

		//Bean mapping
		BeanMappingBuilder beanMappingBuilder = new BeanMappingBuilder() {
			@Override
			protected void configure() {

				String dateFormat = "MM/dd/yyyy HH:mm";

				mapping(SourceObject.class, 
						DestinationObject.class, 
						TypeMappingOptions.wildcard(true), 
						TypeMappingOptions.dateFormat(dateFormat)).
						fields("date", "date");
			}
		};

		//Example
		DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
		dozerBeanMapper.addMapping(beanMappingBuilder);

		SourceObject src = new SourceObject();
		src.setDate("08/06/2017 11:45");
		
		DestinationObject dest = dozerBeanMapper.map(src, DestinationObject.class);
		
		System.out.println("DestinationObject : " + dest);
	}
}

Program output.

DestinationObject : DestinationObject [date=Sun Aug 06 11:45:00 IST 2017]

8. Spring DozerBeanMapper example

In case, you have Spring framework in your project, you can create the org.dozer.DozerBeanMapper bean created and use it as below example.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="dozerBeanMapper" class="org.dozer.DozerBeanMapper">
		<property name="mappingFiles">
			<list>
				<value>mappings/student-mapper.xml</value>
			</list>
		</property>
	</bean>
	
</beans>

How to use DozerBeanMapper to map beans.

package com.example.howtodoinjava.dozer.demo.withspring;

import org.dozer.DozerBeanMapper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.example.howtodoinjava.dozer.models.DestinationObject;
import com.example.howtodoinjava.dozer.models.SourceObject;
import com.example.howtodoinjava.dozer.models.Student;

public class DemoWithDozerBeanMapper {

	public static void main(String[] args) {
		SourceObject sourceObject = new SourceObject();
		sourceObject.setName("Sajal");
		sourceObject.setAddress("India");

		sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));
		sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));
		sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
		DozerBeanMapper beanMapper = (DozerBeanMapper) applicationContext.getBean("dozerBeanMapper");

		DestinationObject destinationObject = beanMapper.map(sourceObject, DestinationObject.class);
		
		System.out.println(destinationObject);
	}
}

Program output.

DestinationObject [name=Sajal, address=India, pupils=[
 StudentVO [name=S1, batchName=C1, homeAddress=diffField1],
 StudentVO [name=S2, batchName=C2, homeAddress=diffField2], 
 StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]
]

Please notice that Dozer has successfully copied all the fields from SourceObject to DestinationObject class.

9. Summary

So in this dozer tutorial, we have seen how we can configure Dozer and how we can use Dozer for a simple use case. We have also seen to create dozer custom converters as well as how we can declare mappings in API style using BeanMappingBuilder.

Happy Learning!!!