Automatically Mapping Java Objects

Automatically Mapping Java ObjectsIn this article we aim to clarify why sometimes it’s important to map two different classes and how it’s possible to do it by building the simplest possible mapping manager step-by-step. Design choices / constraints often produce a considerable amount of mechanical work which we will try to minimize by automatically mapping Java objects.

By “mapping objects” we mean copy one object state to another object. Sometimes the mapping is transparent, considering that both objects have the same attributes, but often it happens between two objects with different attributes. Those who are familiar with Web API development probably already faced a situation where your resource representation is similar but not identical to the domain model or even when you don’t want to expose your domain objects to any other layer within your system. In these cases we generally create a component to abstract this mapping task, which also allow us to reuse it in other parts of the system.

An advantage of having a mapping component (e.g. to map your domain to DTO and vice versa) is not as apparent when you are only supporting a single mapping, but as the number of mappings increases, having that code isolated from the domain helps to keep the domain simpler and leaner. You won’t be cluttering your domain with a lot of extra weight.

Hands On

To clarify the mapping idea, let’s start creating two domain classes (Customer and Address) and one DTO class (CustomerDTO).

Domain classes

DTO class

Once we have the picture of our classes, consider the following problems:

  • How can we convert a Customer object to a CustomerDTO object (filling all attributes, including the addressId)?
  • How can we convert a CustomerDTO object to a Customer object (filling all attributes, including the address.id)?

Step 1 – Manually mapping using pure Java

This approach is the most basic form to map an object to another. As you will see bellow, the code is absolutely mechanic. There’s no logic at all and it’s too verbose, even for a simple couple of domain classes with no more than 5 attributes.

Step 2 – Extracting the mapping logic to a new component

In this version we are going to improve the previous solution by extracting the mapping logic to an external class in order to simplify the mapping caller’s method and enabling the reuse of the mapper. At this point we are still using pure Java. Despite of this improvement, this mapping is still manual, verbose and error-prone. So far we are only talking about two domain classes but can you imagine this class handling fifty domain classes? It would be a really huge class.

Step 3 – Automatically mapping using Orika Mapper

The last improvement in our mapper will be by far the most interesting one: make the mapping in the most automated way without losing control. To achieve this goal we are going to use a library called Orika Mapper. Orika is a Java Bean mapping framework that recursively copies (among other capabilities) data from one object to another. It can be very useful when developing multi-layered applications, as I mentioned earlier.

First of all we need to include the Orika library in our project dependencies. In this example I will use Maven but it would be pretty much the same for Gradle and Ivy.

Once the Orika library is available in the classpath, we can refactor the MapperManager class to expose a generic map method that will receive two parameters, the first one is the instance that will be mapped and the other is the desired output class. The constructor was used to initialize the mapperFactory attribute (MapperFactory is a class provided by the Orika DSL) and register the bidirectional mapping from the Customer class to the CustomerDTO class.

As you could observe above when the name of the attributes match, in both source and target objects, the mapping is automatically defined as soon as you invoke the “byDefault” method. The only customization we needed to do in our mapping was teach Orika how to map the customer address, from “Address” to “Integer”, using the “field” method. I won’t explain in details how to use the Orika DSL, mainly because their documentation is massive and plenty of examples.

Using this approach for any type of conversion we will always use the map method. For each new “desired conversion” you will just need to register a new class map in the constructor.

Conclusion

As well written in the Orika docs, when we are working with different tools/frameworks/libraries, it is common to find that we need to convert objects into different formats to accommodate different APIs, or we may even need to convert formats between distinct architectural layers of our own for design reasons; to accomplish this, we are left to the rather boring task of writing mapping code to copy the values from one type to another.

Looking at this through another perspective — as problem solvers — it’s important to avoid any unnecessary effort to write code that doesn’t really matter to the business. These repetitive and mechanical tasks are generally not worth and may be the entrance door for many bugs in our systems. The reuse of good libraries not only keeps our code focused on the domain problem you are working on but also increases the stability of the system, once the majority of these libraries keeps a good test coverage and bug fixes.