Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Java Bean Mapper Comparison

In my development experience i always had to use a software layer to copy the values from a Bean to another bean. This technique, can be applied in many ways and it is very useful when you have to decouple a domain model from another, or simply to decouple client model from server model. For example, in an layered architecture, it is not reccomended to expose directly the entity read from DB on a facade layer.
It is reccomended instead, to expose a model that we'll call the DT Model; an instance of a class from this domain is a Data Transfer Object, or simply a DTO. A DTO is the object that you really want to expose and to keep the other objects in the internal layers there is one way: you have to copy the values from the internal bean to the DTO.

Mapping techniques

A Java Bean Mapping framework solves these problems, there are many kinds of java bean mapping techiniques:

  • Simple Pojo Mapping
  • Flattening mapping
  • Projection mapping
  • Complex Pojo Mapping

Probably you will need all of them and for each you have to deal with some aspects such as:

  • Property mapping (deep, skip, recursive)
  • Custom type conversion
  • Validation

Runtime VS Compile-time Conversion

For every developer the best way to do the hard work is to automate the process of copying values from source bean to the destination bean. There area many frameworks that do automatic mapping with a little effort by developers, the only difference between the various frameworks is how they store and collect the mapping info. There are two main type of mapping conversion:

  • Runtime automated conversion
  • Compile time automated conversion

The first uses informations written in XML files or in Java annotations to know what type and what fields it has to map. Tipically these types of mapper use reflection to scan java bean structure and to recognize which field has to be read from source class and in which field it has to write the value to target class.

The second uses informations given, such as Java annotations or XML config files, to simply generate Java source code or to enhance a class file respectively before or during compilation phase.
This techinique ensure good performance because the hard work is made only one time, during compilation. However class enhancement can be done at runtime too, when application starts for first time.

What i have to use?

If you have to copy properties and you don't need all other aspects in Bean Mapping you are free to use tools like Apache Common BeanUtils or Spring BeanUtils.

Dozer

The most used mapping framework i know is Dozer from Apache Software Foundation. Dozer can be used with XML Files or Annotation to write mappings. A common usage is to declare the mapper in CDI or Spring container and to load all mappings from XML files, every time you need to map beans you can call the map method:

<bean class="org.dozer.spring.DozerBeanMapperFactoryBean">
   <property 
                  name="mappingFiles" 
                  value="classpath*:/dto-mapping-*.xml">
   </property>        
 </bean>

@Inject
private Mapper mapper;

DestObject destObject  = mapper.map(sourceObject, DestObject.class); 

Basically Dozer can do many other things: you can specify BeanFactory or custom contervers and when you declare a mapping it enables to write deep property map to implement flattening or projections conversion.
Dozer makes heavy use of reflection to scan properties and to do method invocation of getters and setters.

ModelMapper

Another bean mapping framework i used is ModelMapper. An intelligent model mapping framework, it uses some conventions on field names to determine how data should be mapped. For example if you have:

// Assume getters and setters on each class
class Source {
 Vehicle vehicle;
 Equipment equipment;
}

class Vehicle {
  String type;
  String model; 
}

class Equipment {
  String code;
  String description;
}

you can map properties in a flat object like this:

// Assume getters and setters
class TransportDTO {
  String vehicleType;
  String vehicleModel;
  String vehicleEquipmentDescription;
}

assuming you have a Vehicle instance, the mapper will automatically generate a TransportDTO for you:

ModelMapper modelMapper = new ModelMapper();
TransportDTO  trDTO = modelMapper.map(vehicle, TransportDTO.class);

MapStruct

I really love this framework beacuse basically it makes use of code generation to do the mapping in a static way. The generated mapping is based on a simple java method invocation thus is faster than reflection base mapping framework. MapStruct make use of annotation processor for generating source code and can be easily plugged to the most used build tools like Maven, Gradle or Ant.
MapStruct has a nice Java8 implementation, to integrate it with Gradle you can use this script:

ext {
    javaLanguageLevel = '1.8'
    generatedMapperSourcesDir = "${buildDir}/generated-src/mapstruct/main"
}

sourceCompatibility = rootProject.javaLanguageLevel

configurations {
    mapstruct
}

dependencies {
    compile( 'org.mapstruct:mapstruct-jdk8:1.0.0.Final' )
    mapstruct( 'org.mapstruct:mapstruct-processor:1.0.0.Final' )
}

sourceSets.main {
    ext.originalJavaSrcDirs = java.srcDirs
    java.srcDir "${generatedMapperSourcesDir}"
}

task generateMainMapperClasses(type: JavaCompile) {
    ext.aptDumpDir = file( "${buildDir}/tmp/apt/mapstruct" )
    destinationDir = aptDumpDir

    classpath = compileJava.classpath + configurations.mapstruct
    source = sourceSets.main.originalJavaSrcDirs
    ext.sourceDestDir = file ( "$generatedMapperSourcesDir" )

    options.define(
        compilerArgs: [
            "-nowarn",
            "-proc:only",
            "-encoding", "UTF-8",
            "-processor", "org.mapstruct.ap.MappingProcessor",
            "-s", sourceDestDir.absolutePath,
            "-source", rootProject.javaLanguageLevel,
            "-target", rootProject.javaLanguageLevel,
        ]
    );

    inputs.dir source
    outputs.dir generatedMapperSourcesDir;
    doFirst {
         sourceDestDir.mkdirs()
    }
    doLast {
        aptDumpDir.delete()
    }
}

compileJava.dependsOn generateMainMapperClasses

For defining a mapper with MapStruct you have to write a simple java interface with one or more map methods and annotate it with a @Mapper annotation and annotate methods with Mappings annotations to give the mappings rule:

@Mapper(defaultComponentModel="spring")
public interface VehicleMapper{

    @Mappings({
        @Mapping(source = "vehicle.type", target = "vehicleType"),
        @Mapping(source = "vehicle.equipment.desc", target = "vehicleEquipDesc")
    })
    TransportDTO vehicleToTransport(Vehicle v);    
}

When you compile the Mapper interface MapStruct will generate a Java class with a default name (in this case VehicleMapperImpl). The vehicleToTransport method can be invoked to do the mapping. Another useful thing is the CDI/Spring integration, simply adding the defaultComponentModel attribute on the interface, the generated source will contains CDI or Spring annotations so the Mapper can be injected in your SpringBeans or EJB.

Conclusions

If you don't have particular constraints i believe that Mapstruct is definitely the best way to realize Java Bean Mapping since it has the same Dozer features but it is more fast.



This post first appeared on Programming And Applications Development: Blog | Luigi's Dev Corner, please read the originial post: here

Share the post

Java Bean Mapper Comparison

×

Subscribe to Programming And Applications Development: Blog | Luigi's Dev Corner

Get updates delivered right to your inbox!

Thank you for your subscription

×