Thursday 10 February 2011

How to use Dozer for automatic Java Bean mapping - quickstart with Maven & Eclipse

Introduction

This step-to-step article describes how to create simple Dozer-enabled application. Dozer is very useful Java Bean to Java Bean mapper, which automatiacally (and recursively) copies fields' values from one object to another. For example, you can use it to automatiacally copy data from Entity object to Dto object. 

Prerequisites
  • JDK 6, 
  • Eclipse IDE with m2eclipse plugin, 
  • Maven 2 (standalone or bundled with Eclipse Helios).
    Table of contents
    1. Create Eclipse project.
    2. How to use default Dozer mapping.
    3. How to configure Dozer mapping.
    4. Summary

      Create Eclipse project

      Start your Eclipse IDE and create a new project. Click File > New > Project...
      Select Maven Project and click Next.


      Select Create a simple project (skip archetype selection) checkbox, and click Next again.


      Fill out all Artifact fields (Group Id, Artifact Id, Version, Name) and click Next.


      On the next form, you need to add two dependencies to the project. First one will be Dozer library. Click Add button, and search for net.sf.dozer dependency. If found, select it on the list and click OK button.


      You will also need JUnit 4 and slf4j-api library. Click Add button again, search for JUnit, select it on the list and add to the project by clicking OK button. Search also for slf4j-api library and add it to the project. When you are done, click Finish.



      How to use default Dozer mapping

      Ok, we have the project, so now we try to use Dozer. What we want to do is to copy fields' values from one object to another. What is great - Dozer requires no configuration if these fields have the same names. Only constraint you should have in mind is that Dozer expects JavaBean class with setters, getters and public no-arg constructor. Let's see how it works!

      Select src/main/java directory and click New Java class button.


      Create App class. In this class we will use dozer for rewriting objects' fields. Fill out Package and Name fields, and click Finish button.


      Leave App class empty for now, and in the same pacakage create another class - SimilarObject1. Add two String fields to this class - firstName and lastName. To generate setters, getters and constructors, click somewhere in the SimilarObject1 editor, press Alt+Shift+S, choose Generate Constructors from Superclass and click OK.


      Press Alt+Shift+S again and choose Generate Constructor using Fiels. Select both fields and click OK.


      Press Alt+Shift+S for the last time and choose Generate Getters and Setters. Click Select All button and click OK.


      SimilarObject1 class should now look like this:
      package pl.bzawadka.poc.dozer;
      
      public class SimilarObject1 {
          private String firstName;
          private String lastName;
      
          public SimilarObject1() {
              super();
          }
      
          public SimilarObject1(String firstName, String lastName) {
              super();
              this.firstName = firstName;
              this.lastName = lastName;
          }
      
          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;
          }
      }
      

      In the same package create second class. This class will contain the same fields as first one. 
      SimilarObject2 class should look like this:
      package pl.bzawadka.poc.dozer;
      
      public class SimilarObject2 {
          private String firstName;
          private String lastName;
      
          public SimilarObject2() {
              super();
          }
      
          public SimilarObject2(String firstName, String lastName) {
              super();
              this.firstName = firstName;
              this.lastName = lastName;
          }
      
          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;
          }
      }
      

      Now it is high time to update App class. To use Dozer, you have to instantiate it's DozerBeanMapper class and invoke map method. And that is all you have to do! Fields in the destination object will be set with values from the source object.
      App class should look like this:

      package pl.bzawadka.poc.dozer;
      
      import org.dozer.DozerBeanMapper;
      import org.dozer.Mapper;
      
      /**
       * Dozer proof of concept
       * 
       */
      public class App {
      
          public static void rewriteSimilar(SimilarObject1 source, SimilarObject2 destination) {
              Mapper mapper = new DozerBeanMapper();
              mapper.map(source, destination);
          }
      
      }
      

      Now we will write a test to check whether rewriteSimilar method works. Create AppTest class in src/test/java directory.
      AppTest class should look like this:

      package pl.bzawadka.poc.dozer;
      
      import static org.junit.Assert.assertEquals;
      
      import org.junit.Test;
      
      /**
       * Unit test for simple App.
       */
      public class AppTest {
      
          @Test
          public void testRewriteSimilar() {
              SimilarObject1 obj1 = new SimilarObject1("dafi", "duck");
              SimilarObject2 obj2 = new SimilarObject2();
      
              App.rewriteSimilar(obj1, obj2);
      
              assertEquals(obj1.getFirstName(), obj2.getFirstName());
              assertEquals(obj1.getLastName(), obj2.getLastName());
          }
      
      }
      
      Let's test our rewriteSimilar method. Click Run Configurations button...


      ... and create new Maven Build configuration. Double click Maven Build option. Fill out Name and choose our project by clicking Browse Workspace... button. Type clean test in Goals field. Click Apply and Run.


      Check Console output - BUILD SUCCESS means, that Dozer automatically filled out our destination object fields. It works!



      How to configure Dozer mapping

      Dozer requires no configuration if objects' fields have the same names. If fields have different names, you need to create xml configuration file.

      Let's create a new class, with slightly different fields (name instead of firstName and latestName instead of lastName).
       
      DifferentObject class should look like this:

      package pl.bzawadka.poc.dozer;
      
      public class DifferentObject {
          private String name;
          private String lastestName;
      
          public DifferentObject() {
          }
      
          public DifferentObject(String name, String lastestName) {
              super();
              this.name = name;
              this.lastestName = lastestName;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getLastestName() {
              return lastestName;
          }
      
          public void setLastestName(String lastestName) {
              this.lastestName = lastestName;
          }
      }
      

      To create configuration file, right-click on the src/main/resources directory and select New > File.


      Type dozer-mapping.xml in File name field.


      Edit this file. <class-a> and <class-b> elements define which classes will be mapped. For each mapped class field, <field> element must exists. In our case, first <field> element defines that SimilarObject1.firstName will be mapped into DifferentObject.lastName.
      dozer-mapping.xml  class should look like this:
      <?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>pl.bzawadka.poc.dozer.SimilarObject1</class-a>
              <class-b>pl.bzawadka.poc.dozer.DifferentObject</class-b>
              <field>
                  <a>firstName</a>
                  <b>name</b>
              </field>
              <field>
                  <a>lastName</a>
                  <b>lastestName</b>
              </field>
          </mapping>
      
      </mappings>
      

      Let's add a new method do App class. This time DozerBeanMapper constructor will take List of configuration files as parameter. You will also need two new imports (java.util.ArrayList, java.util.List).

          public static void rewriteDifferent(SimilarObject1 source, DifferentObject destination) {
              List<String> mappingFiles = new ArrayList<String>();
              mappingFiles.add("dozer-mapping.xml");
              Mapper mapper = new DozerBeanMapper(mappingFiles);
              mapper.map(source, destination);
          }
      

      Add the following test to AppTest class:
          @Test
          public void testRewriteDifferent() {
              SimilarObject1 obj1 = new SimilarObject1("dafi", "duck");
              DifferentObject obj3 = new DifferentObject();
      
              App.rewriteDifferent(obj1, obj3);
      
              assertEquals(obj1.getFirstName(), obj3.getName());
              assertEquals(obj1.getLastName(), obj3.getLastestName());
          }
      

      Run the build (Alt+Shift+X and press M). The result should be like the following:


      Dozer worked again!


      Summary

      In this article you have learnt how to use Dozer library for automatic Java Bean mapping. By default, Dozer requires no configuration. If you want to map objects' fields with different names, xml configuration file is required. For more information, visit project page.