By May 16, 2022

Top 8 Frameworks to Help Java Developers with Bean Mapping

As a newbie Java programmer, you might want to know how you can build a large application without using tons of similar code that can exhaust you.

Building a large application on Java that includes multiple layers requires models like domain, persistence, and data transfer objects (DTOs). Applications usually consist of different but similar object models where the data may be similar but the structure and objectives differ. It is crucial to converting different types of data or objects for business decisions or data hiding while executing a large application.

With object mapping, it becomes easier to convert one model to another while isolating separate models.

Although it is common to map one object to another object, it can often be iterative and tedious as both the classes have similar or the same mapped properties. Fortunately, there are several Java mapping frameworks that one can use to copy data from one object to another recursively.

But before moving on to the mapping frameworks, let’s get started with the basics of mapping in Java.

What is JavaBean?

JavaBeans are Java classes that encapsulate different objects into one object or bean. Beans should be serializable (i.e. conversion of the object state into a byte stream), should have a public no-arg constructor, and the properties must be private with public getter and setter methods.

Let’s look at an example that shows how a JavaBean class is structured.

  1. package mypack;
  2. public class Student implements java.io.Serializable{
  3. private int id;
  4. private String name;
  5. public Student(){}
  6. public void setId(int id){this.id=id;}
  7. public int getId(){return id;}
  8. public void setName(String name){this.name=name;}
  9. public String getName(){return name;}
  10. }

Now to access JavaBean, getter and setter methods are used as follows:

  1. package mypack;
  2. public class Test{
  3. public static void main(String args[]){
  4. Student s=new Student(); //object is created
  5. s.setName(“Anna”); //setting value to the object
  6. System.out.println(e.getName());
  7. }}

Although JavaBeans can be exposed to other applications to reuse the software components, JavaBeans are mutable (i.e. can be changed after creation) so they cannot benefit from immutable objects (like Strings in Java that can’t be changed after creation). When you want to encapsulate (hide) data, it requires a get method to return its values and set methods to sets or update its value. However, creating getter and setter methods for every property can lead to repeated code in multiple areas with few to no variations also known as boilerplates.

That’s where the bean mapping framework comes to play its role in project development.

What is Bean Mapping Framework?

Sometimes building enterprise-level projects can be difficult due to unstructured, broad goals and nonlinear workflows that make the app more complex. Besides, completing certain functionalities of external systems’ legacy components requires the transformation of objects with similar structures like external service response to domain objects and domain objects into external service requests which is difficult to obtain manually.

Let’s look into a real-world scenario, these requests and response objects might include numerous columns. To copy one bean/object into another with manual code will require tons of code lines such as destination.setABC(source.getABC()) which is recursive and error-prone.

If you want to overcome the complexity and repetitiveness of writing similar lines of code for copying data from one bean to another, a bean mapping framework is highly useful as it offers simple configuration and fewer lines of code that streamlines your work.

The Top Frameworks For Mapping in Java

Now that you know what JavaBean and Bean mapping frameworks in Java are and why they are being used in the first place. It is time to learn the top Java Bean Mapping frameworks that you can use for mapping while working on your next project.

dOOv

Domain Object Oriented Validation (dOOv) is an API used for domain model validation and mapping. dOOv uses code generations, annotations, and type-safe Domain-specific language (DSL) to make mapping and validation easier and more rapid. Saving you both time and effort.

dOOV is composed of a dOOv core, dOOv generator, and dOOv assertions where the core contains Abstract Syntax Tree (AST), DST, and annotations, generator consists of code generators for field information and model-map, and assertions include AssertJ assertions.

For the following sections on recommended frameworks, I will offer an overview explanation of the framework and then coded segments for you to get started with whenever you’re ready.

  • Annotate Domain model
public class User {

    @TestPath(field = TestFieldId.FIRST_NAME, readable = "user first name")
    private String firstName;

    @TestPath(field = TestFieldId.LAST_NAME, readable = "user last name")
    private String lastName;

    @TestPath(field = TestFieldId.DATEOFDATE, readable = "user date of birth")
    private LocalDate birthDate;

}

  • Generate DSL code with elements like userFirstName, userLastName, and userDateIOfBirth
  • Write and execute validation rules
ValidationRule rule = DOOV.when(userDateOfBirth.ageAt(today()).greaterOrEquals(18)).validate();

You must write code in the instantiated model to execute it, where the instantiated model is the creation of a real instance or particular realization of abstraction such as a class of objects.

// Execute the DSL on the model
DslModel model = new SampleModelWrapper(sampleModel);
Result result = rule.executeOn(model);
if (result.isFalse()) {
  // do stuff on the model that didn't validate
}
  • Map

To map an object with others using dOOv you will write codes as:

MappingRegistry mappings = mappings(
  map(userFirstName, userLastName)
    .using(biConverter((first, last) -> first + " " + last))
    .to(accountFullName),
  map(userDateOfBirth)
    .using(date -> Years.yearsBetween(date, LocalDate.now()))
    .to(accountAge));

Two instantiated models can then be used to execute the mapping code.

DslModel model1 = new SampleModelWrapper(sampleModel1);
DslModel model2 = new SampleModelWrapper(sampleModel2);
Context context = mappings.executeOn(model1, model2);
// do stuff with model2 new values
  • Test validation rules

Assertions are available in the doov-assertions jar. Since AssertJ is required, you can use the assertThat syntax.

ValidationRule rule = DOOV.when(userFirstName.isNotNull().or(userLastName.isNull())).validate();
assertThat(rule).validates(model).hasFailedNodeEmpty();

JMapper

JMapper is the Java mapping framework based on Javassist that uses byte code manipulation for fast mapping. JMapper offers the benefits of both dynamic conversions, relational mapping, and static code performance at zero memory consumption. It takes input in two classes, Destination (instance that will be created or modified) and Source (instance that contains data). So before mapping, you need to configure one class between Source and Destination and then invoke the method Get method.

Annotation

class Destination {

  @JMap
  String id;
  @JMap("SourceField")
  String destinationField;
  String other;
  // getter and setter
 }

 class Source {
   String id;
   String SourceField;
   String other;
   // getter and setter
 }

To invoke the GetDestination method, you will create and use an XML file as follows:

<jmapper>
  <class name="it.jmapper.bean.Destination">
    <attribute name="id">
      <value name="id"/>
    </attribute>
    <attribute name="destinationField">
      <value name="SourceField">
    </attribute>
  </class>
</jmapper>

For execution you will create API as below:

JMapperAPI jmapperAPI = new JMapperAPI()
    .add(mappedClass(Destination.class)
             .add(attribute("id")
                     .value("id"))
             .add(attribute("destinationField")
                     .value("SourceField")));

MapStruct

MapStruct is one of the most used Java annotation processors for performant and type-safe JavaBeans classes mappers. It comes with built-in conversions and sensible defaults that don’t bother you while implementing or configuring specific behavior.

MapStruct simplifies mapping by automating it as much as possible. It generates bean mappings compile time to ensure high performance, thorough error checking, and fast feedback.

MapStruct, an annotation processor, is plugged into the compiler of Java and can be used in your preferred Integrated Development Environment (IDE) or command-line builds like Gradle and Maven.

To use MapStruct, you need to define the mapper interface declaring all the required methods of mapping.

Let’s assume you have two classes one that represents cars and the other accompanying data transfer object (DTO) as below:

  • Car.java
public class Car {

    private String make;
    private int numberOfSeats;
    private CarType type;

    //constructor, getters, setters, etc.
}
  • CarDTO.java

public class CarDto {

    private String make;
    private int seatCount;
    private String type;

    //constructor, getters, setters, etc.
}

Both the classes are almost identical except the attributes for seat count have different names and the enumeration type attribute in the Car class is the plain string in the DTO.

To create a mapper for carDTO, the mapper interface will be defined as:

@Mapper
public interface TestMapper {

    TestMapper INSTANCE = Mappers.getMapper( TestMapper.class );

    @Mapping(target = "seatCount", source = "numberOfSeats")
    TestDto testToTestDto(Test test);
}

Using the interface you have created for the mapper, object mapping can be done easily in a type-safe way as:

@Test
public void shouldMapCarToDto() {
    //given
    Car car = new Car( "Morris", 5, CarType.SEDAN );

    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );

    //then
    assertThat( carDto ).isNotNull();
    assertThat( carDto.getMake() ).isEqualTo( "Morris" );
    assertThat( carDto.getSeatCount() ).isEqualTo( 5 );
    assertThat( carDto.getType() ).isEqualTo( "SEDAN" );
}

ModelMapper

An intelligent mapping library, ModelMapper is capable of mapping objects automatically. It provides a simple refactoring safe API and uses a conventional approach to handle certain use cases.

ModelMapper is a great Java Bean Mapper as it makes the object mapping easier by determining how one object can map to another through conventions automatically, so you don’t have to worry about manual mapping.

You can setup ModelMapper in Maven as follows:

<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>3.0.0</version>
</dependency>

To map an object with others using ModelMapper you can create source and destination model codes as:

Source Code:

// Assume getters and setters on each class
class Order {
  Customer customer;
  Address billingAddress;
}

class Customer {
  Name name;
}

class Name {
  String firstName;
  String lastName;
}

class Address {
  String street;
  String city;
}

Destination code:

// Assume getters and setters
class OrderDTO {
  String customerFirstName;
  String customerLastName;
  String billingStreet;
  String billingCity;
}

For executing ModelMapper implied map, use something like:

ModelMapper modelMapper = new ModelMapper();
OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);

At the time of the calling map method, the source model and destination model codes will be analyzed to identify the properties-simplicity based on the matching configuration and strategy. Only after that data is mapped to other objects.

reMap

ReMap is a Java mapping library that helps developers in simplifying object conversions attribute by attribute while reducing the mapper classes unit testing.

ReMap is easily accessible through JCenter and Maven Central. Below is how you will map source and destination type in-app.

Mapping.from(Customer.class)
    .to(Person.class)
    .omitInSource(Customer::getAddress)
    .omitInDestination(Person::getBodyHeight)
    .reassign(Customer::getTitle)
        .to(Person::getSalutation)
    .replace(Customer::getGender, Person::getGender)
        .withSkipWhenNull(Gender::valueOf)
    .mapper();

Orika

Orika is a JavaBean to Bean mapping framework that iteratively copies data from one object to another. It is highly recommended while developing a multi-layered web application, because of how Orika builds effective, comprehensive, and robust solutions for Java Bean mapping.

Orika makes the mapping of Java Beans much faster by using byte code generators with minimal overhead.

To map two beans or objects with each other first declare destination and source classes as follows:

class BasicPerson {
  private String name;
  private int age;
  private Date birthDate;
  // getters/setters omitted
}
class BasicPersonDto { 
  private String fullName;
  private int currentAge;
  private Date birthDate;
  // getters/setters omitted
}

Next, map the two classes as:

  mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
   .field("name", "fullName")
   .field("age", "currentAge")
   .register();

Orika mapping can also be customized if you create custom Mappers, Convertors, and ObjectFactory types where mappers can be used to apply properties of an object to another; ObjectFactory can be used to construct an instance in context to mapping, and Converter takes complete control of mapping process. Make an efficient Jave Bean Mapper for your next project.

Selma

Stupid Simple Statically Linked Mapper (AKA Selma) is an annotation processor-based bean to bean mapper for Java. It generates Java Code to handle field to field mapping and also works as a runtime library to invoke generated mappers.

To see Selma in action, follow the given steps:

@Mapper
public interface SelmaMapper {

    // Immutable mapping
    OutBean asOutBean(InBean source);

    // Update graph
    OutBean updateOutBean(InBean source, OutBean destination);

To use Selma for mapping, we will:

  SelmaMapper mapper = Selma.mapper(SelmaMapper.class);

    OutBean res = mapper.asOutBean(in);

    // Or
    OutBean dest = dao.getById(42);

    OutBean res = mapper.updateOutBean(in, dest);
    // res is the value for the bean destination

Dozer

Dozer is a Java mapping framework that copies data from one object to another using APL/XML configuration and annotations. It is an open-source, robust, flexible, configurable, reusable, and generic mapping framework that supports complex, simple, implicit, explicit, bi-directional, and recursive mapping of JavaBeans. Dozer is ideal if you want to avoid unnecessary codes used while copying data from one bean to another. It not only supports the mapping of beans but also converts data types for mapping classes with DTOs automatically.

Using Maven, you can add Dozer in your project simply through:

<dependency>

    <groupId>com.github.dozermapper</groupId>

    <artifactId>dozer-core</artifactId>

    <version>6.5.2</version>

</dependency>

Create Source and Destination classes:

<mapping>
  <class-a>yourpackage.SourceClassName</class-a>
  <class-b>yourpackage.DestinationClassName</class-b>
    <field>
      <a>yourSourceFieldName</a>
      <b>yourDestinationFieldName</b>
    </field>
</mapping>
And map these classes as:
SourceClassName sourceObject = new SourceClassName();
sourceObject.setYourSourceFieldName("Dozer");

Mapper mapper = DozerBeanMapperBuilder.buildDefault();
DestinationClassName destObject = mapper.map(sourceObject, 
DestinationClassName.class);

assertTrue(destObject.getYourDestinationFieldName().equals(sourceObject.getYourSourceFieldName()));

Make JavaBeans Mapping Easier with Frameworks

Java Mapping frameworks are remarkable and crucial when it comes to developing software or web applications tailored to meet the needs of large-scale businesses.

Adopting Java Mapping frameworks will make it easier to copy data objects from one bean to another at a fast pace with more accuracy and minimum effort.

These top frameworks of Java Mapping like MapStruck, reMap, dozer, and dOOv will help you in acquiring a professional advantage in the future.

Key takeaways:

  • With object mapping, it becomes easier to convert one model to another while isolating separate models.
  • Bean mapping frameworks are highly useful as it offers simple configuration and fewer lines of code that streamlines your work.
  • Java Bean Mapping frameworks that you can use for mapping while working on your next project are dOOv, JMapper, MapStruct, ModelMapper, reMap, Orika, Selma, and Dozer.
  • To map two objects you need to create source and destination classes.
  • Java Bean Frameworks are easily accessible through command-line builds like Maven and Gradle.
About the author

Mahipal Nehra

Mahipal Nehra is the Technical Writer for Decipher Zone Software, a Java Development Company, where he learns about new technologies and trends regularly. With an experience of 11+ years, he wants to share his learnings with the programmers to help them learn about different technologies such as Java, JavaScript & its frameworks, UML, BPMN, BPEL, APIs, and so much more.