Introduction to Dozer


Bhaskar S 11/01/2013


Overview

When we are solving an Enterprise problem that involves Integration, often times we run into the problem where the target system we are integrating with expects an object of Type-B while the source has a different object of Type-A.

We typically hand-code a Utility class that creates an object of Type-B from Type-A by copying some of the data members (fields) of Type-A to Type-B.

This can get cumbersome if we have deep object nexting in an object of Type-A and/or Type-B.

Wonder if there is any open-source Java framework for this ??? Enter Dozer !!!

Dozer is an open-source Java framework that allows one to recursively copy a Java bean of Type-A to a Java bean of Type-B by mapping fields of Type-A to Type-B.

Dozer and its Dependencies

Download Dozer from the following site:

Dozer has dependencies on the following additional open-source Java frameworks:

Hands-on with Dozer

We will demonstrate the use of Dozer with a simple contact object.

In our first example, we will map the Java object Contact1A to the Java object Contact1B.

The following is an interface that defines the various contact types:

Listing.1
package com.polarsparc.dozer;

public interface ContactType {
public static String EMAIL = "EMAIL";
public static String HOME = "HOME";
public static String WORK = "WORK";
public static String MOBILE = "MOBILE";
}

The following is the implementation of the Java object Contact1A. Notice that the contact information is stored in a java.util.Map:

Listing.2
package com.polarsparc.dozer;

import java.util.Map;
import java.util.HashMap;

public class Contact1A {
private String first;
private String last;

private Map<String, String> contacts;

public Contact1A() {
contacts = new HashMap<String, String>();
}

public String getFirst() {
return first;
}

public void setFirst(String first) {
this.first = first;
}

public String getLast() {
return last;
}

public void setLast(String last) {
this.last = last;
}

public Map<String, String> getContacts() {
return contacts;
}

public void setContacts(Map<String, String> contacts) {
this.contacts = contacts;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("[Contact1A] :: Name = ");
sb.append(first);
sb.append(" ");
sb.append(last);
sb.append(", Contacts = ");
sb.append(contacts);

return sb.toString();
}
}

The following is the implementation of the Java object Contact1B, which is a regular Java bean:

Listing.3
package com.polarsparc.dozer;

public class Contact1B {
private String firstName;
private String lastName;
private String email;
private String home;
private String work;
private String mobile;

public String getFirstName() {
return firstName;
}

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

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 getHome() {
return home;
}

public void setHome(String home) {
this.home = home;
}

public String getWork() {
return work;
}

public void setWork(String work) {
this.work = work;
}

public String getMobile() {
return mobile;
}

public void setMobile(String mobile) {
this.mobile = mobile;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("[Contact1B] :: Name = ");
sb.append(firstName);
sb.append(" ");
sb.append(lastName);
sb.append(", Contacts = [");
sb.append(email);
sb.append(", ");
sb.append(home);
sb.append(", ");
sb.append(work);
sb.append(", ");
sb.append(mobile);
sb.append("]");

return sb.toString();
}
}

Since the Java objects Contact1A and Contact1B don't have any common field names, we will need a custom mapping XML file to map fields from Contact1A to Contact1B as shown below:

Listing.4
<?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">

<configuration>
<stop-on-errors>true</stop-on-errors>
</configuration>

<mapping type="bi-directional">
<class-a>com.polarsparc.dozer.Contact1A</class-a>
<class-b>com.polarsparc.dozer.Contact1B</class-b>
<field>
<a>first</a>
<b>firstName</b>
</field>
<field>
<a>last</a>
<b>lastName</b>
</field>
<field>
<a key="EMAIL">contacts</a>
<b>email</b>
</field>
<field>
<a key="HOME">contacts</a>
<b>home</b>
</field>
<field>
<a key="WORK">contacts</a>
<b>work</b>
</field>
<field>
<a key="MOBILE">contacts</a>
<b>mobile</b>
</field>
</mapping>
</mappings>

The custom mapping XML file shown in Listing.4 above consists of a root element <mappings>, which is a container for two other elements:

The <mapping> element, in turn, has the following:

From our example of the custom mapping XML file from Listing.4, we gather the following:

The following is the test code for using Dozer, to map from an instance of Contact1A to Contact1B and vice-versa:

Listing.5
package com.polarsparc.dozer;

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

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

public class TestCont1A2Cont1B {
private static String DOZER_MAPPING = "contact-1-mapping.xml";

public static void main(String[] args) {
Contact1A c1 = createContact1A();
Contact1B c2 = new Contact1B();

List<String> list = new ArrayList<String>();
list.add(DOZER_MAPPING);

Mapper mapper = new DozerBeanMapper(list);

mapper.map(c1, c2);

System.out.printf("C1 >> %s\n", c1);
System.out.printf("C2 >> %s\n", c2);

Contact1A c3 = new Contact1A();

mapper.map(c2, c3);

System.out.printf("C2 >> %s\n", c2);
System.out.printf("C3 >> %s\n", c3);
}

private static Contact1A createContact1A() {
Contact1A c1 = new Contact1A();

c1.setFirst("John");
c1.setLast("Doe");

c1.getContacts().put(ContactType.EMAIL, "john.doe@earth.com");
c1.getContacts().put(ContactType.HOME, "123-456-7890");
c1.getContacts().put(ContactType.WORK, "800-123-4567");
c1.getContacts().put(ContactType.MOBILE, "999-888-7777");

return c1;
}
}

The core class from the Dozer Java framework that provides the desired bean mapping functionality is the class DozerBeanMapper.

Compiling and executing the test code from Listing.5 produces the following output:

Output.1

Nov 02, 2013 4:40:50 PM org.dozer.config.GlobalSettings loadGlobalSettings
INFO: Trying to find Dozer configuration file: dozer.properties
Nov 02, 2013 4:40:50 PM org.dozer.config.GlobalSettings loadGlobalSettings
WARNING: Dozer configuration file not found: dozer.properties. Using defaults for all Dozer global properties.
Nov 02, 2013 4:40:50 PM org.dozer.DozerInitializer init
INFO: Initializing Dozer. Version: 5.4.0, Thread Name: main
Nov 02, 2013 4:40:50 PM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerStatisticsController] auto registered with the Platform MBean Server
Nov 02, 2013 4:40:50 PM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerAdminController] auto registered with the Platform MBean Server
Nov 02, 2013 4:40:50 PM org.dozer.DozerBeanMapper init
INFO: Initializing a new instance of dozer bean mapper.
Nov 02, 2013 4:40:50 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using the following xml files to load custom mappings for the bean mapper instance: [contact-1-mapping.xml]
Nov 02, 2013 4:40:50 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Trying to find xml mapping file: contact-1-mapping.xml
Nov 02, 2013 4:40:50 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using URL [file:/home/bswamina/Projects/Java/Dozer/resources/contact-1-mapping.xml] to load custom xml mappings
Nov 02, 2013 4:40:50 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Successfully loaded custom xml mappings from URL: [file:/home/bswamina/Projects/Java/Dozer/resources/contact-1-mapping.xml]
C1 >> [Contact1A] :: Name = John Doe, Contacts = {HOME=123-456-7890, MOBILE=999-888-7777, WORK=800-123-4567, EMAIL=john.doe@earth.com}
C2 >> [Contact1B] :: Name = John Doe, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C2 >> [Contact1B] :: Name = John Doe, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C3 >> [Contact1A] :: Name = John Doe, Contacts = {HOME=123-456-7890, MOBILE=999-888-7777, WORK=800-123-4567, EMAIL=john.doe@earth.com}

We have sucessfully demonstrated our first Dozer example.

Next, we will move on to our second example, where we will map the Java object Contact2A to the Java object Contact2B.

The following is the implementation of the Java object ContactInfo which encapsulates the contact information as a JavaBean:

Listing.6
package com.polarsparc.dozer;

import java.util.Date;

public class ContactInfo {
private Date dob;

private String email;

private String mobile;
private String home;
private String work;

public Date getDob() {
return dob;
}

public void setDob(Date dob) {
this.dob = dob;
}

public String getEmail() {
return email;
}

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

public String getMobile() {
return mobile;
}

public void setMobile(String mobile) {
this.mobile = mobile;
}

public String getHome() {
return home;
}

public void setHome(String home) {
this.home = home;
}

public String getWork() {
return work;
}

public void setWork(String work) {
this.work = work;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("Birthdate = ");
sb.append(dob);
sb.append(", Contacts = [");
sb.append(email);
sb.append(", ");
sb.append(home);
sb.append(", ");
sb.append(work);
sb.append(", ");
sb.append(mobile);
sb.append("]");

return sb.toString();
}
}

The following is the implementation of the Java object Contact2A. Notice that this class has a reference to an instance of ContactInfo which encapsulates the contact information:

Listing.7
package com.polarsparc.dozer;

public class Contact2A {
private String first;
private String last;

private ContactInfo info;

public Contact2A() {
info = new ContactInfo();
}

public String getFirst() {
return first;
}

public void setFirst(String first) {
this.first = first;
}

public String getLast() {
return last;
}

public void setLast(String last) {
this.last = last;
}

public ContactInfo getInfo() {
return info;
}

public void setInfo(ContactInfo info) {
this.info = info;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("[Contact2A] :: Name = ");
sb.append(first);
sb.append(" ");
sb.append(last);
sb.append(", Contacts = ");
sb.append(info);

return sb.toString();
}
}

The following is the implementation of the Java object Contact2B, which is a regular Java bean:

Listing.8
package com.polarsparc.dozer;

public class Contact2B {
private String first;
private String last;
private String dob;
private String email;
private String home;
private String work;
private String mobile;

public String getFirstName() {
return first;
}

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

public String getLastName() {
return last;
}

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

public String getDob() {
return dob;
}

public void setDob(String dob) {
this.dob = dob;
}

public String getEmail() {
return email;
}

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

public String getHome() {
return home;
}

public void setHome(String home) {
this.home = home;
}

public String getWork() {
return work;
}

public void setWork(String work) {
this.work = work;
}

public String getMobile() {
return mobile;
}

public void setMobile(String mobile) {
this.mobile = mobile;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("[Contact2B] :: Name = ");
sb.append(first);
sb.append(" ");
sb.append(last);
sb.append(", Birthdate = ");
sb.append(dob);
sb.append(", Contacts = [");
sb.append(email);
sb.append(", ");
sb.append(home);
sb.append(", ");
sb.append(work);
sb.append(", ");
sb.append(mobile);
sb.append("]");

return sb.toString();
}

}

Since the Java objects Contact2A and Contact2B don't have any common properties, we will need a custom mapping XML file to map fields from Contact2A to Contact2B as shown below:

Listing.9
<?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">

<configuration>
<stop-on-errors>true</stop-on-errors>
</configuration>

<mapping>
<class-a>com.polarsparc.dozer.Contact2A</class-a>
<class-b>com.polarsparc.dozer.Contact2B</class-b>
<field>
<a>first</a>
<b get-method="getFirstName" set-method="setFirstName">first</b>
</field>
<field>
<a>last</a>
<b get-method="getLastName" set-method="setLastName">last</b>
</field>
<field>
<a>info.dob</a>
<b date-format="MM/dd/yyyy">dob</b>
</field>
<field>
<a>info.email</a>
<b>email</b>
</field>
<field>
<a>info.home</a>
<b>home</b>
</field>
<field>
<a>info.work</a>
<b>work</b>
</field>
<field>
<a>info.mobile</a>
<b>mobile</b>
</field>
</mapping>
</mappings>

From our example of the custom mapping XML file from Listing.9, we gather the following:

The following is the test code for using Dozer, to map from an instance of Contact2A to Contact2B and vice-versa:

Listing.10
package com.polarsparc.dozer;

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

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

public class TestCont1A2Cont1B {
private static String DOZER_MAPPING = "contact-1-mapping.xml";

public static void main(String[] args) {
Contact1A c1 = createContact1A();
Contact1B c2 = new Contact1B();

List<String> list = new ArrayList<String>();
list.add(DOZER_MAPPING);

Mapper mapper = new DozerBeanMapper(list);

mapper.map(c1, c2);

System.out.printf("C1 >> %s\n", c1);
System.out.printf("C2 >> %s\n", c2);

Contact1A c3 = new Contact1A();

mapper.map(c2, c3);

System.out.printf("C2 >> %s\n", c2);
System.out.printf("C3 >> %s\n", c3);
}

private static Contact1A createContact1A() {
Contact1A c1 = new Contact1A();

c1.setFirst("John");
c1.setLast("Doe");

c1.getContacts().put(ContactType.EMAIL, "john.doe@earth.com");
c1.getContacts().put(ContactType.HOME, "123-456-7890");
c1.getContacts().put(ContactType.WORK, "800-123-4567");
c1.getContacts().put(ContactType.MOBILE, "999-888-7777");

return c1;
}
}

Compiling and executing the test code from Listing.10 produces the following output:

Output.2

Nov 02, 2013 6:29:22 PM org.dozer.config.GlobalSettings loadGlobalSettings
INFO: Trying to find Dozer configuration file: dozer.properties
Nov 02, 2013 6:29:22 PM org.dozer.config.GlobalSettings loadGlobalSettings
WARNING: Dozer configuration file not found: dozer.properties. Using defaults for all Dozer global properties.
Nov 02, 2013 6:29:22 PM org.dozer.DozerInitializer init
INFO: Initializing Dozer. Version: 5.4.0, Thread Name: main
Nov 02, 2013 6:29:22 PM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerStatisticsController] auto registered with the Platform MBean Server
Nov 02, 2013 6:29:22 PM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerAdminController] auto registered with the Platform MBean Server
Nov 02, 2013 6:29:22 PM org.dozer.DozerBeanMapper init
INFO: Initializing a new instance of dozer bean mapper.
Nov 02, 2013 6:29:22 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using the following xml files to load custom mappings for the bean mapper instance: [contact-2-mapping.xml]
Nov 02, 2013 6:29:22 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Trying to find xml mapping file: contact-2-mapping.xml
Nov 02, 2013 6:29:22 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using URL [file:/home/bswamina/Projects/Java/Dozer/resources/contact-2-mapping.xml] to load custom xml mappings
Nov 02, 2013 6:29:22 PM org.dozer.DozerBeanMapper loadFromFiles
INFO: Successfully loaded custom xml mappings from URL: [file:/home/bswamina/Projects/Java/Dozer/resources/contact-2-mapping.xml]
C1 >> [Contact2A] :: Name = John Doe, Contacts = Birthdate = Thu Jan 01 00:00:00 EST 1970, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C2 >> [Contact2B] :: Name = John Doe, Birthdate = 01/01/1970, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C2 >> [Contact2B] :: Name = John Doe, Birthdate = 01/01/1970, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C3 >> [Contact2A] :: Name = John Doe, Contacts = Birthdate = Thu Jan 01 00:00:00 EST 1970, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]

We have sucessfully demonstrated our second Dozer example.

Finally, we will move on to our third and last example, where we will map the Java object Contact3A to the Java object Contact2B.

The following is an enum ContactEnum that defines the various contact types:

Listing.11
package com.polarsparc.dozer;

public enum ContactEnum {
EMAIL("EMAIL"),
HOME("HOME"),
WORK("WORK"),
MOBILE("MOBILE");

private final String value;

private ContactEnum(String value) {
this.value = value;
}

@Override
public String toString(){
return value;
}
}

The following is the implementation of the Java object Contact3A. Notice that the contact information is stored in a java.util.Map (with the key of type ContactEnum):

Listing.12
package com.polarsparc.dozer;

import java.util.Map;
import java.util.HashMap;

public class Contact3A {
private String first;
private String last;

private Map<ContactEnum, String> contacts;

public Contact3A() {
contacts = new HashMap<ContactEnum, String>();
}

public String getFirst() {
return first;
}

public void setFirst(String first) {
this.first = first;
}

public String getLast() {
return last;
}

public void setLast(String last) {
this.last = last;
}

public Map<ContactEnum, String> getContacts() {
return contacts;
}

public void setContacts(Map<ContactEnum, String> contacts) {
this.contacts = contacts;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();

sb.append("[Contact3A] :: Name = ");
sb.append(first);
sb.append(" ");
sb.append(last);
sb.append(", Contacts = ");
sb.append(contacts);

return sb.toString();
}
}

For the Java object implementation for Contact2B, refer to the Listing.8 above.

Since the Java objects Contact3A and Contact2B don't have any property names in common, we will need a custom mapping XML file to map fields from Contact3A to Contact2B and vice-versa as shown below:

Listing.13
<?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">

<configuration>
<stop-on-errors>true</stop-on-errors>
</configuration>

<mapping map-id="3to2" type="one-way">
<class-a>com.polarsparc.dozer.Contact3A</class-a>
<class-b>com.polarsparc.dozer.Contact2B</class-b>
<field>
<a>first</a>
<b>firstName</b>
</field>
<field>
<a>last</a>
<b>lastName</b>
</field>
<field custom-converter="com.polarsparc.dozer._3Ato2BConverter"
custom-converter-param="EMAIL">
<a>contacts</a>
<b>email</b>
</field>
<field custom-converter="com.polarsparc.dozer._3Ato2BConverter"
custom-converter-param="HOME">
<a>contacts</a>
<b>home</b>
</field>
<field custom-converter="com.polarsparc.dozer._3Ato2BConverter"
custom-converter-param="WORK">
<a>contacts</a>
<b>work</b>
</field>
<field custom-converter="com.polarsparc.dozer._3Ato2BConverter"
custom-converter-param="MOBILE">
<a>contacts</a>
<b>mobile</b>
</field>
</mapping>

<mapping map-id="2to3" type="one-way">
<class-a>com.polarsparc.dozer.Contact2B</class-a>
<class-b>com.polarsparc.dozer.Contact3A</class-b>
<field>
<a>firstName</a>
<b>first</b>
</field>
<field>
<a>lastName</a>
<b>last</b>
</field>
<field custom-converter="com.polarsparc.dozer._2Bto3AConverter"
custom-converter-param="EMAIL">
<a>email</a>
<b>contacts</b>
</field>
<field custom-converter="com.polarsparc.dozer._2Bto3AConverter"
custom-converter-param="HOME">
<a>home</a>
<b>contacts</b>
</field>
<field custom-converter="com.polarsparc.dozer._2Bto3AConverter"
custom-converter-param="WORK">
<a>work</a>
<b>contacts</b>
</field>
<field custom-converter="com.polarsparc.dozer._2Bto3AConverter"
custom-converter-param="MOBILE">
<a>mobile</a>
<b>contacts</b>
</field>
</mapping>
</mappings>

The custom mapping XML file in Listing.13 above seems a bit more complex than the prior ones. One of the reasons for this is due to the fact that we have a custom enum (of type ContactEnum) as the key for the contact types in the field contacts in Contact3A.

In Dozer (at least currently), there is no way of specifying the type of the key for a java.util.Map field. This is one of those cases where its upon us to write custom converters to map fields between a source and a target.

A side-effect of this is that we have to define two one-way mappings - one for mapping from Contact3A to Contact2B and the other for mapping from Contact2B to Contact3A.

The following is the implementation of a custom field converter _3Ato2BConverter for mapping a contact type from Contact3A to a field in Contact2B:

Listing.14
package com.polarsparc.dozer;

import java.util.Map;

import org.dozer.ConfigurableCustomConverter;

public class _3Ato2BConverter implements ConfigurableCustomConverter {
private String param;

@Override
public Object convert(Object targetValue, Object sourceValue,
Class<?> targetClass, Class<?> sourceClass) {
System.out.printf("_3Ato2BConverter: param = %s\n", param);

if (sourceValue != null) {
@SuppressWarnings("unchecked")
Map<ContactEnum, String> contacts = (Map<ContactEnum, String>)sourceValue;

String value = contacts.get(ContactEnum.valueOf(param));

System.out.printf("_3Ato2BConverter: value = %s\n", value);

return value;
}

return null;
}

@Override
public void setParameter(String param) {
this.param = param;
}
}

The following is the implementation of another custom field converter _2Bto3AConverter for mapping a field from Contact2B to a contact type in Contact3A:

Listing.15
package com.polarsparc.dozer;

import java.util.Map;

import org.dozer.ConfigurableCustomConverter;

public class _2Bto3AConverter implements ConfigurableCustomConverter {
private String param;

@Override
public Object convert(Object targetValue, Object sourceValue,
Class<?> targetClass, Class<?> sourceClass) {
System.out.printf("_2Bto3AConverter: param = %s\n", param);

if (sourceValue != null && targetValue != null) {
@SuppressWarnings("unchecked")
Map<ContactEnum, String> contacts = (Map<ContactEnum, String>)targetValue;

contacts.put(ContactEnum.valueOf(param), (String)sourceValue);

return contacts;
}

return null;
}

@Override
public void setParameter(String param) {
this.param = param;
}
}

To implement a custom converter (field or class) in Dozer, one needs to implement the org.dozer.ConfigurableCustomConverter interface. This is evident from the Listing.14 and Listing.15 above.

From our example of the custom mapping XML file from Listing.13, we gather the following:

The following is the test code for using Dozer, to map from an instance of Contact3A to Contact2B and vice-versa:

Listing.16
package com.polarsparc.dozer;

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

import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

public class TestCont3A2Cont2B {
private static String DOZER_MAPPING = "contact-3-mapping.xml";

public static void main(String[] args) {
Contact3A c1 = createContact3A();
Contact2B c2 = new Contact2B();

List<String> list = new ArrayList<String>();
list.add(DOZER_MAPPING);

Mapper mapper = new DozerBeanMapper(list);

mapper.map(c1, c2, "3to2");

System.out.printf("C1 >> %s\n", c1);
System.out.printf("C2 >> %s\n", c2);

Contact3A c3 = new Contact3A();

mapper.map(c2, c3, "2to3");

System.out.printf("C2 >> %s\n", c2);
System.out.printf("C3 >> %s\n", c3);
}

private static Contact3A createContact3A() {
Contact3A c1 = new Contact3A();

c1.setFirst("John");
c1.setLast("Doe");

c1.getContacts().put(ContactEnum.EMAIL, "john.doe@earth.com");
c1.getContacts().put(ContactEnum.HOME, "123-456-7890");
c1.getContacts().put(ContactEnum.WORK, "800-123-4567");
c1.getContacts().put(ContactEnum.MOBILE, "999-888-7777");

return c1;
}
}

Compiling and executing the test code from Listing.16 produces the following output:

Output.3

Nov 03, 2013 12:37:05 AM org.dozer.config.GlobalSettings loadGlobalSettings
INFO: Trying to find Dozer configuration file: dozer.properties
Nov 03, 2013 12:37:05 AM org.dozer.config.GlobalSettings loadGlobalSettings
WARNING: Dozer configuration file not found: dozer.properties. Using defaults for all Dozer global properties.
Nov 03, 2013 12:37:05 AM org.dozer.DozerInitializer init
INFO: Initializing Dozer. Version: 5.4.0, Thread Name: main
Nov 03, 2013 12:37:05 AM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerStatisticsController] auto registered with the Platform MBean Server
Nov 03, 2013 12:37:05 AM org.dozer.jmx.JMXPlatformImpl register
INFO: Dozer JMX MBean [org.dozer.jmx:type=DozerAdminController] auto registered with the Platform MBean Server
Nov 03, 2013 12:37:05 AM org.dozer.DozerBeanMapper init
INFO: Initializing a new instance of dozer bean mapper.
Nov 03, 2013 12:37:05 AM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using the following xml files to load custom mappings for the bean mapper instance: [contact-3-mapping.xml]
Nov 03, 2013 12:37:05 AM org.dozer.DozerBeanMapper loadFromFiles
INFO: Trying to find xml mapping file: contact-3-mapping.xml
Nov 03, 2013 12:37:05 AM org.dozer.DozerBeanMapper loadFromFiles
INFO: Using URL [file:/home/bswamina/Projects/Java/Dozer/resources/contact-3-mapping.xml] to load custom xml mappings
Nov 03, 2013 12:37:05 AM org.dozer.DozerBeanMapper loadFromFiles
INFO: Successfully loaded custom xml mappings from URL: [file:/home/bswamina/Projects/Java/Dozer/resources/contact-3-mapping.xml]
_3Ato2BConverter: param = EMAIL
_3Ato2BConverter: value = john.doe@earth.com
_3Ato2BConverter: param = HOME
_3Ato2BConverter: value = 123-456-7890
_3Ato2BConverter: param = WORK
_3Ato2BConverter: value = 800-123-4567
_3Ato2BConverter: param = MOBILE
_3Ato2BConverter: value = 999-888-7777
C1 >> [Contact3A] :: Name = John Doe, Contacts = {WORK=800-123-4567, EMAIL=john.doe@earth.com, HOME=123-456-7890, MOBILE=999-888-7777}
C2 >> [Contact2B] :: Name = John Doe, Birthdate = null, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
_2Bto3AConverter: param = EMAIL
_2Bto3AConverter: param = HOME
_2Bto3AConverter: param = WORK
_2Bto3AConverter: param = MOBILE
C2 >> [Contact2B] :: Name = John Doe, Birthdate = null, Contacts = [john.doe@earth.com, 123-456-7890, 800-123-4567, 999-888-7777]
C3 >> [Contact3A] :: Name = John Doe, Contacts = {WORK=800-123-4567, EMAIL=john.doe@earth.com, HOME=123-456-7890, MOBILE=999-888-7777}

We have sucessfully demonstrated our third and final Dozer example.