Bean Manipulation using Dozer Framework
Introduction
As you know you can copy file or folder from source location to destination location in any operating system. Have you ever thought about copy the java object which is basically a POJO ? There are many instances where you need to copy the source bean contents to a destination bean. I am not taking about the copy constructor, shallow or deep copy or clone of an object. In some circumstances you have to copy the contents of the source bean to a destination with or without filter conditions. There can be n number of reasons to do this and there are many ways you can achieve it. In this small post I will provide you a glimpse of a framework called “Dozer” to achieve this functionality in an easiest and robust manner.
Technicalities
This small article will provide you the utility of “Dozer” framework copy a source bean to a destination bean. Before we start, let us think about a situation that you have a source bean which contains lot of fields and the source bean belongs to a different project or module. Now you want to expose the bean to the outside world as a part of your web service REST service development. It is not advisable to do it. There may be the following reasons.
- The source system does not allow doing it because of security breach.
- The source bean is not serialized and a final class.
- The source bean has lot of fields; some of them are not required.
- The source bean is very heavy and contains lot of nested beans.
- The source bean has fields of different types which may not be required for other system.
The above may be some other specific reasons, think about a situation, you want to make a REST call or web service call to get the minimal account details of a person. But the source system has a bean called “AccountBean” which contains many sensitive information like person’s internet banking password, profile password, pan no or social security number, total balance etc. You want to develop an application where you want to expose only account’s address details, name and home branch of the bank. This is a required situation where you want to have your custom defined bean which should be exposed to outside based upon the account number. In this case you have to copy the original bean to your custom defined bean. To achieve this functionality you can do it in the following ways.
- Write code to manually copy the contents of the source bean to destination bean.
- Use java Reflection or Introspection utility to copy from source to destination bean.
- Use an available framework which does the copy automatically.
In this case we will learn about a framework which helps us to copy the contents of a source bean to destination bean. The framework called “Dozer” is very popular and flexible to use and integrate in the application. You will find more documentation on Dozer in various internet sites. In this post I will provide you very basic and practical usage of Dozer.
Let’s quickly learn the usage of Dozer in the following scenarios.
- Copy source Plain/Flat bean to destination Plain/Flat bean
- Copy collections
- Bi-directional bean copy
- Copy flat bean to nested bean and vice versa
- Copy bean with custom conversion.
Copy source Plain/Flat bean to destination Plain/Flat bean
This is the simplest case where we have a source POJO and we want to copy into destination POJO. Let us consider the following java code.
Structure of source POJO below.
package com.ddlab.rnd.type1.srcpkg; /** * The Class Person is used as a source bean for Person which contains Address * object. * * @author <a href="mailto:debadatta.mishra@gmail.com">Debadatta Mishra</a> * @since 2013 */ public class Person { /** The name. */ private String name; /** The age. */ private int age; /** The adrs. */ private Address adrs; // All getter and setter method below }
Structure of destination POJO below.
package com.ddlab.rnd.type1.destnpkg; /** * The Class Person1 is used as destination bean for Person1 which contains * Addrss1 object * * @author Debadatta Mishra * @since 2013 */ public class Person1 { /** The name1. */ private String name1; /** The age1. */ private int age1; /** The adrs1. */ private Address1 adrs1; //All getter setter method below }
Let us see the dozer mapping file called “dozerMapping.xml”
<?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 map-id="a"> <class-a>com.ddlab.rnd.type1.srcpkg.Person</class-a> <class-b>com.ddlab.rnd.type1.destnpkg.Person1</class-b> <field> <a>name</a> <b>name1</b> </field> <field> <a>age</a> <b>age1</b> </field> <field> <a>adrs.doorNo</a> <b>adrs1.doorNo1</b> </field> <field> <a>adrs.stName</a> <b>adrs1.stName1</b> </field> </mapping> </mappings>
The above xml configuration file looks very intuitive as <class-a > refers to source bean and < class-b> refers to destination bean. The other field <a> refers to the property of source bean and <b> refers to the property of the destination bean.
Let us see the final code which does the bean mapping.
List<String> list = new ArrayList<String>(); // Add the mapping configuration list.add("dozerMapping.xml"); // Add to DozerMapper Mapper mapper = new DozerBeanMapper(list); mapper.map(p, p1, "a");
Now it is done, it looks very simple and provides many powerful features. You have remember the following few things for bean copy using “Dozer” framework.
- Source bean
- Destination bean
- Dozer mapping file configuration
- Mapping configuration should contain source POJO class with proper package name
- Mapping configuration should contain destination POJO class with proper package name
- Mapping configuration should have proper exact property name what you have defined in the java class
The mapping configuration provides the following benefits.
- You can change the property name as and when required and it does not require to build the application.
- You can add the property in the java class as and when required.
- You can have one or many property files for specific requirements.
- You can edit and remove the mapping as and when required.
- You can also configure the mapping in Spring application ie spring configuration file.
Copy collections
There are certain occasions where you want to copy list of source type to list of destination type. The list may contain different types of objects. Let us see a typical java code below.
package com.ddlab.dozer.type2.srcpkg; import java.util.List; /** * The Class AddressList is used as a source List object which contains object * of type Address. * * @author <a href="mailto:debadatta.mishra@gmail.com">Debadatta Mishra</a> * @since 2013 */ public class AddressList { /** The adrs list. */ private List<Address> adrsList; /** * Gets the adrs list. * * @return the adrs list */ public List<Address> getAdrsList() { return adrsList; } /** * Sets the adrs list. * * @param adrsList * the new adrs list */ public void setAdrsList(List<Address> adrsList) { this.adrsList = adrsList; } }
In the above case the list contains list of Address type objects. Let us learn how to achieve.
First of all create a mapping between Address objects from source to destination and then create a mapping between source list to destination list. Let us see the mapping configuration file.
<?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 map-id="k"> <class-a>com.ddlab.dozer.type2.srcpkg.Address</class-a> <class-b>com.ddlab.dozer.type2.destnpkg.AddressBean</class-b> <field> <a>name</a> <b>name</b> </field> <field > <a>id</a> <b>id</b> </field> </mapping> <mapping map-id="q1" type="one-way" relationship-type="non-cumulative"> <class-a>com.ddlab.dozer.type2.srcpkg.AddressList</class-a> <class-b>com.ddlab.dozer.type2.destnpkg.AddressBeanList</class-b> <field map-id="k"> <a>adrsList</a> <b>adrsList</b> </field> </mapping> </mappings>
To copy the list object, you can use the same code which is in the first case.
Bi-directional bean copy
In this case you need to have a mapping which does bean copy in both the direction. Let us think about a situation where you want to convert the internal java bean to a custom bean to expose as web service and finally you receive the data in the custom bean and convert it into internal bean. It is not advisable to write another mapping. “Dozer” provides attributes in the xml mapping configuration to copy in both the direction based upon the requirement. I provide the attribute required to mention in dozer configuration.
<mapping map-id="k" type="bi-directional"> <!-- Other field mapping --> </mapping>
The above attribute type (type="bi-directional"
) provides the flexibility of copying objects in both direction.
Copy flat bean to nested bean and vice versa
Based upon the project requirement, you may have a complex bean which contains nested other java beans. You may have to copy the complex bean to a simple type or vice versa. Let us see the mapping configuration.
<?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 map-id="a"> <class-a>com.ddlab.dozer.type4.srcpkg.MyPerson</class-a> <class-b>com.ddlab.dozer.type4.destnpkg.Person1</class-b> <!-- Other field info --> <field> <a>doorNo</a> <b>adrs1.doorNo1</b> </field> <field> <a>stName</a> <b>adrs1.stName1</b> </field> <field> <a>cname</a> <b>adrs1.country.name</b> </field> <field> <a>ccode</a> <b>adrs1.country.code</b> </field> <field> <a>fd</a> <b>adrs1.country.bd</b> </field> </mapping> </mappings>
In the above case mark the line in red colour. To have a hands-on example, refer to the following mapping configuration file.
- flat2NestedBeanMapping.xml
- nestedBeanMapping2Flat.xml
Refer to the following packages for this.
- com.ddlab.dozer.type4.destnpkg
- com.ddlab.dozer.type4.srcpkg
You can download the complete eclipse project from the following link: https://www.dropbox.com/s/j6ep7wq7lalfe2k/dozerbeancopy.zip
Copy bean with custom conversion.
This is a very typical and a complex condition which occurs during the time of development. Imagine that you have java bean which contains specific fields like date in JodaTime api, object of type UUID, field of type BigInteger etc and you have a java bean with all primitive type fields. In this case you have to use custom converters and inject in “Dozer” mapping configuration file so that “Dozer” will automatically copy the java bean with proper field types.
Let us see the structure of the mapping file.
<?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> <custom-converters> <converter type="com.ddlab.dozer.type5.converters.Date2JodaDateConverter"> <class-a>org.joda.time.LocalDate</class-a> <class-b>java.util.Date</class-b> </converter> </custom-converters> </configuration> <mapping map-id="k" type="bi-directional"> <class-a>com.ddlab.dozer.type5.srcpkg.SrcBean</class-a> <class-b>com.ddlab.dozer.type5.destnpkg.DestnBean</class-b> <!-- For UUID --> <field copy-by-reference="true"> <a>idKey</a> <b>uid</b> </field> <!-- For java.util.Date to org.joda.time.LocalDate --> <field> <a>utilDate</a> <b>jodaDate</b> </field> <!-- For double to java.math.BigDecimal --> <field> <a>amount</a> <b>bigDecimal</b> </field> </mapping> </mappings>
Dozer provides an interface called “org.dozer.CustomConverter” which enables to do custom conversion based upon our requirements. I provide below a small code snippet.
package com.ddlab.dozer.type5.converters; import org.dozer.CustomConverter; import org.dozer.MappingException; import org.joda.time.LocalDate; /** * The Class Date2JodaDateConverter is used as a Dozer custom converter for * converting java.util.Date to Jodatime LocalDate. * * @author <a href="mailto:debadatta.mishra@gmail.com">Debadatta Mishra</a> * @since 2013 */ public class Date2JodaDateConverter implements CustomConverter { /* * (non-Javadoc) * * @see org.dozer.CustomConverter#convert(java.lang.Object, * java.lang.Object, java.lang.Class, java.lang.Class) */ @Override public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, @SuppressWarnings("rawtypes") Class destinationClass, @SuppressWarnings("rawtypes") Class sourceClass) { if (sourceFieldValue == null) { return null; } if (sourceFieldValue instanceof java.util.Date) { java.util.Date utilDate = (java.util.Date) sourceFieldValue; LocalDate localDate = new LocalDate(utilDate.getTime()); return localDate; } throw new MappingException("Misconfigured/unsupported mapping"); } }
To know more about refer to the following packages.
- com.ddlab.dozer.type5.converters
- com.ddlab.dozer.type5.destnpkg
- com.ddlab.dozer.type5.srcpkg
How to do
To work with “Dozer” framework, you have to use the following jar files in your classpath.
- commons-beanutils-1.7.jar
- commons-lang-2.4.jar
- commons-logging-1.1.1.jar
- commons-logging-api-1.1.1.jar
- dozer-5.3.2.jar
- joda-time-2.2.jar
- log4j-1.2.16.jar
- log4j-over-slf4j-1.6.1.jar
- slf4j-api-1.6.1.jar
- slf4j-jdk14-1.6.1.jar
- slf4j-simple-1.6.1.jar
You have to download “Dozer” framework from the following link: http://dozer.sourceforge.net/ . Dozer also provides eclipse plugin to ease the work of mapping.
Related Packages and Configuration File
Plain bean to Plain Bean
- com.ddlab.rnd.type1.destnpkg (from src)
- com.ddlab.rnd.type1.srcpkg (from src)
- com.ddlab.rnd.type1 (from test)
- dozerMapping.xml (Mapping Configuration)
Collections Copy
- com.ddlab.dozer.type2.destnpkg (from src)
- com.ddlab.dozer.type2.srcpkg (from src)
- com.ddlab.dozer.type2 (from test)
- list2ListMapping.xml (Mapping Configuration)
Bi-directional Bean copy
- com.ddlab.dozer.type3 (from test)
- dozerBidirectionalMapping1.xml (Mapping Configuration)
Flat to Nested Bean/Nested Bean to Flat Bean
- com.ddlab.dozer.type4.destnpkg (from src)
- com.ddlab.dozer.type4.srcpkg (from src)
- com.ddlab.dozer.type4 (from test)
- flat2NestedBeanMapping.xml (Mapping Configuration)
- nestedBeanMapping2Flat.xml (Mapping Configuration)
Custom Converter
- com.ddlab.dozer.type5.converters (from src)
- com.ddlab.dozer.type5.destnpkg (from src)
- com.ddlab.dozer.type5.srcpkg (from src)
- com.ddlab.dozer.type5 (from test)
- dozercustomconvertermapping.xml
Download
You can download the complete eclipse project from the following dropbox site: https://www.dropbox.com/s/j6ep7wq7lalfe2k/dozerbeancopy.zip. You can easily configure the Eclipse IDE easily by importing the project.
Conclusion
I hope you have enjoyed my small post about the usage of Dozer framework for bean copy in java. Download the complete project and go through the source code to understand the concept and its usage. Based upon the complexity and design , you can decide whether to use this concept. For any kind of issues and error you can contact me at debadatta.mishra@gmail.com .
Resources and References
There are other frameworks also available provide bean manipulation in a more or less way. I found “Dozer” framework suitable in various grounds. There is also similar kind of framework called “Nomin” which provides mapping similar to that of “Dozer” by providing configuration in a properties file. I provide below the various links for your references.
- http://dozer.sourceforge.net/documentation/gettingstarted.html
- http://nomin.sourceforge.net/
- http://modelmapper.org/
- http://code.google.com/p/orika/
- http://morph.sourceforge.net/
- https://code.google.com/p/omapper/
i think one of big disadvantage of dozer is annotation
using annotation is very weak and have some bug in that
hello, Dozer is the reference point, but when we write the xml file it takes much time and it is error-prone, the performance are low, annotation are supported only for simple mapping… I suggest you take a look at JMapper Framework: http://code.google.com/p/jmapper-framework/ With JMapper you can decide to map with annotations or in xml format, execute creation or enrichment of the target instance, explicit conversions, 1 to N and N to 1 relationships and much more. This framework is based on javassist library, the mapping is created at runtime, with 0 memory consuption and with performance of static code. –… Read more »
It is always a debate whether to follow annotations or XML configuration. However Dozer performs well in case XML configuration. Author of this article has already mentioned it. In case dynamic changes and various factors Dozer is considered as the light weight. You can check about Dozer in various sites.
when we are performing mapping with dozer, it is not loading source classfile and giving below exception, Although sourceclassfile is available at that path mentioned. Could you please suggest.
org.dozer.MappingException: java.lang.ClassNotFoundException: com.java.sourceclassfile
at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82)
at org.dozer.util.DefaultClassLoader.loadClass(DefaultClassLoader.java:43)
at org.dozer.util.MappingUtils.loadClass(MappingUtils.java:224)
at org.dozer.loader.DozerBuilder$MappingBuilder.classA(DozerBuilder.java:129)
at org.dozer.loader.xml.XMLParser.parseMapping(XMLParser.java:190)
at org.dozer.loader.xml.XMLParser.read(XMLParser.java:137)
at org.dozer.loader.xml.XMLParser.read(XMLParser.java:43)
at org.dozer.loader.xml.MappingStreamReader.read(MappingStreamReader.java:51)
at org.dozer.loader.xml.MappingFileReader.read(MappingFileReader.java:58)
….
Thanks for writing concise article covering so many options. The link https://www.dropbox.com/s/j6ep7wq7lalfe2k/dozerbeancopy.zip is broken.
Thanks for this article, showing that Dozer is feature full. I would say that Dozer is not refactoring proof and since it runs only at runtime using reflection, it is way too much resource consuming and weak. For an unknown reason, you have not tested a single specific field that you need to get mapped, with Dozer you can discover buggy behavior in production. But there is another way to handle those mappings, if really like reflection, you should have a look to Orika https://code.google.com/p/orika/, the other way is to use something like Selma http://xebia-france.github.io/selma/. Selma is a mapping framework… Read more »