I love good software, and Orika is a really interesting project. In this post I’m going to talk about this Java bean mapping framework that I’ve used recently and I highly recommend.
Orika (formerly hosted at google code) claims to be a simpler, lighter and faster Java bean mapping. And it really is.
It allows you to convert objects by copying its attributes from one to another. It performs this by using Java introspection, instead of XML configuration or something like that. It uses code generation to create the mappers, and it has an interesting strategy for its core classes that allows you to optimize the performance.
It is completely configurable, for instance, the java code generator by default is Javassist, but you can use EclipseJdt or even use another provider by implementing the appropriate interface.
Finally, it’s a very well documented project, with clear explanations and useful code.
I really like it.
If you want to try it, just add the next dependency to your maven project:
1 2 3 4 5 |
<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-core</artifactId> <version>1.4.5</version><!-- or latest version --> </dependency> |
Or download the library along with three required libraries:
- javassist (v 3.12.0+)
- slf4j (v 1.5.6+)
- paranamer (v 2.0+)
Main concepts
There are two core classes, the first one is MapperFactory, the class to configure the mappings and to obtain the second core class: MapperFacade, that actually provides the service of a Java bean mapping.
MapperFactory
By using a fluent API, you can construct a MapperFactory via its main implementation, DefaultMapperFactory and its static class helpers intended for building the MapperFactory.
Then you can obtain a ClassMapBuilder from the MapperFactory in order to declare the mapping configuration in a fluent-style, that is: mapping fields (bi-directional by default, or in one direction if you’d rather), excluding fields, specifying constructors and customizing mappings of Lists, Sets, nested fields and so on.
There is a default mapping that maps fields with matching names between two classes, and you can also register the mapping in the MapperFactory (the ClassMapBuilder is built with the very MapperFactory as atribute). Both operations have the appropriate methods to be called.
Let’s see an example:
We have two classes: PersonDTO and Person, and we want to convert one object for the former class to an object of the latter one, so let’s configure the MapperFactory:
1 2 3 4 5 6 7 8 |
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); mapperFactory.classMap(PersonDTO.class, Person.class) //A ClassMapBuilder<PersonDTO, Person> .field("lastNames", "surnames") //Register field mappings .field("streetAddress", "address.street") .field("city", "address.city") .field("postalCode", "address.zipCode") .byDefault() //the remaining fields on both classes should be mapped matching the fields by name .register(); //register the mapping with the MapperFactory. |
The ClassMapBuilder provides interesting mappings for excluding fields, mapping fields in one direction only (as I mentioned above, mapping is by default bi-directional) and so on. See the Declarative Mapping Configuration and Advanced Mapping Configurations for more options.
MapperFacade and BoundMapperFacade
The MapperFacade performs the actual mapping work, for doing so, you have to obtain the MapperFacade from the MapperFactory and then use its map methods. There are two general options, map(objectA, B.class), which will create a new instance of B.class and map the property values of objectA onto it, or map(objectA, objectB), which copies properties from objectA onto objectB, being both of them not null.
Let’s see an example:
1 2 3 4 5 6 7 |
MapperFacade mapper = mapperFactory.getMapperFacade(); PersonDTO personDTO = new PersonDTO(); //Set values here Person person = mapper.map(personDTO, Person.class); //Alternatively: //Person person = new Person(); //mapper.map(personDTO, person); |
The BoundMapperFacade is intended to be used with a pair of types to map and no further customization needed. It provides improved performance over use of the standard MapperFacade and it has the same usage plus a mapReverse method for mapping in the reverse direction.
See below an example:
1 2 3 4 5 6 7 8 9 10 11 |
BoundMapperFacade<PersonDTO, Person> boundMapper = mapperFactory.getMapperFacade(PersonDTO.class, Person.class); PersonDTO personDTO = new PersonDTO(); //Set values here Person person = boundMapper.map(personDTO); //Alternatively: //Person person = new Person(); //boundMapper.map(personDTO, person); //Map in the reverse PersonDTO personDTO = boundMapper.mapReverse(person); //Alternatively with no null objects: //boundMapper.mapReverse(person, personDTO); //curiously, it returns an A object instead of void |
If you’re primarily concerned with the mapping of a particular type to another, and your object graph has no cycles, use BoundMapperFacade because it has better performance, since you avoid the overhead of looking up an appropriate mapping strategy for the fields of the objects to be mapped, that happens when you call the map method.
Performance
The most expensive operations are instantiation and initialization of the MapperFactory, and the MapperFacade which is obtained from it.
Both of them are thread-safe objects, thus singletons or static access for them are a very recommended approach.
For instance, you can consider an static acces to the MapperFactory:
1 2 3 4 5 6 7 8 |
package com.malsolo.orika.test.domain.mappers; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.DefaultMapperFactory; public class BaseMapper { final static MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build(); } |
And then use this class for registering class maps and access to the MapperFacade in a customize way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.malsolo.orika.test.domain.mappers; import com.malsolo.orika.test.domain.Customer; import com.malsolo.orika.test.dto.CustomerDTO; import ma.glasnost.orika.MapperFacade; public enum CustomerMapper { INSTANCE; private final MapperFacade mapperFacade; private CustomerMapper() { BaseMapper.MAPPER_FACTORY.classMap(CustomerDTO.class, Customer.class) .byDefault() .register(); mapperFacade = BaseMapper.MAPPER_FACTORY.getMapperFacade(); } public Customer map(CustomerDTO customerDTO) { return this.mapperFacade.map(customerDTO, Customer.class); } public CustomerDTO map(Customer customer) { return this.mapperFacade.map(customer, CustomerDTO.class); } } |
In this case I’m using two new classes: Customer and CustomerDTO.
Finally, just use this helper classes:
1 2 3 |
CustomerDTO customerDTO = new CustomerDTO(); //Setters at will Customer customer = CustomerMapper.INSTANCE.map(customerDTO); |
How it works and Customization
The best way to understand how Orika works is to read the FAQ, but the source code is very clear and easy to follow, just in case you want to take a deeper look to the details.
“Orika uses reflection to investigate the metadata of the objects to be mapped and then generates byte-code at runtime which is used to map those classes […]”
“Orika mapping is configured via Java code at runtime, via a fluent-style ClassMapBuilder API. An instance is obtained from a MapperFactory which is then used to describe the mapping from one type to another. Finally, the specified ClassMap is registered with the MapperFactory for later use in generating a byte-code mapper.”
To configure Orika, the author recommends to extend the ConfigurableMapper class, and I will use this approach for using Orika with Spring (see below)
If you want to configure the code generation, compilation and so on, see how to do this using the MapperFactory in the next topic.
MapperFactory Configuration
The core class MapperFactory is instantiated as you’ve seen above, by building the provided implementation: DefaultMapperFactory. It uses a set of Strategy and factory objects for resolving constructors, for compiling code (actually, they belong to its inner static class MapperFactoryBuilder that is extended by its other inner static class that you use to instantiate the MapperFactory: the Builder), for resolving properties, and specially for building class maps.
So you can customize all of them after calling Builder() and before the build() method:
1 2 3 4 5 6 7 8 |
new DefaultMapperFactory.Builder() .constructorResolverStrategy(new SimpleConstructorResolverStrategy()) //By default, you can extend it or implement your own ConstructorResolverStrategy .compilerStrategy(new JavassistCompilerStrategy()) //By default, you can extend it, implement your own CompilerStrategy or use EclipseJdtCompilerStrategy .propertyResolverStrategy(new IntrospectorPropertyResolver()) //By default, you can extend it or implement your own PropertyResolverStrategy .classMapBuilderFactory(new ClassMapBuilder.Factory()) //by default. You can use //enabled by default or //enabled by default.Factory .useAutoMapping(true) //enabled by default .mapNulls(true) //enabled by default .build(); |
Custom Mappers
A Mapper<A, B> copies the properties from one object onto another and it’s used internally by Orika (MapperFacade, MapperGenerator and MapperFactory use it, but it isn’t really interesting for this post, actually)
If you want to take control of how properties of one object instance are copied to another object instance (not null), just extends the abstract class CustomMapper<A,B>.
Then, you can register your custom mapper in the MapperFactory via its method registerMapper(Mapper<A, B> mapper).
It’s intended to be used when the mapping behavior configured via the ClassMapBuilder API doesn’t suit your purposes, but only to copy properties, that is, the destination object already exists. If you want to control instantiation, use a CustomConverter or ObjectFactory which both return an instance. See below.
If you need to map nested members of the given object, you can doing so by using the current MapperFacade that it’s accessible via a protected mapperFacade variable.
I’ve used converters in a Spring applications as components that can be scanned and used to configure the MapperFactory by extending ConfigurableMapper as I mentioned above and I’ll show below.
Object Factories
An ObjectFactory<D> instantiates objects. You can implement this interface and register your implementation in the MapperFactory via their method registerObjectFactory (there are a couple of them)
I’ve never used this option.
Custom Converters
A Converter<S, D> combines both ObjectFactory and Mapper together, returning a new instance of the destination type with all properties copied from the source instance.
When you want to take complete control over the instantiation and mapping, just extend CustomConverter<S, D> to create the new instance and to provide it the properties from the source object.
Then, you can register your custom converter in the MapperFactory by obtaining its ConverterFactory via the getConverterFactory() method and then using one of its registerConverter() methods.
I’ve found this option useful when you want to create some hard conversion between classes that has the same meaning in your code but are not really related in terms of Java. Well, it’s a conversion, let’s say, from a date represented in a String and a date that has to be a Calendar. You have to use some formatter for doing so.
It’s also very easy to configure converters as Spring components if you need so.
Using Orika with Spring
Since the Orika core classes MapperFactory and the MapperFacade obtained from it are very expensive to instantiate and initialize, but at the same time are thread-safe, they should be shared as singletons. That is, they are good candidates for being Spring beans with singleton scope.
Let’s start with using spring-framework in a maven project,just add the next dependency to the pom.xml file:
1 2 3 4 5 |
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.1.RELEASE</version><!-- or latest version --> </dependency> |
The Spring application
Let’s create a couple of beans to obtain a Person and a PersonDTO, let’s call them service and repository respectively:
1 2 3 4 5 6 7 8 9 |
package com.malsolo.orika.test.spring; import com.malsolo.orika.test.domain.Person; public interface PersonService { public Person obtainPerson(); } |
1 2 3 4 5 6 7 8 9 |
package com.malsolo.orika.test.spring; import com.malsolo.orika.test.dto.PersonDTO; public interface PersonRepository { public PersonDTO obtainPerson(); } |
And their implementations, the one for the service will use the repository interface, and the one for the repository will be a simple in-memory implementation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.malsolo.orika.test.spring; import com.google.common.collect.ImmutableList; import com.malsolo.orika.test.dto.PersonDTO; import java.util.Random; import org.springframework.stereotype.Repository; @Repository public class PersonRepositoryImpl implements PersonRepository { Random random = new Random(); @Override public PersonDTO findPerson() { return this.createPersonDTO(random.nextLong()); } private PersonDTO createPersonDTO(long l) { PersonDTO dto = new PersonDTO(); dto.setId(l); //More setters here return dto; } } |
Note that the service will need to convert from the DTO to the domain object, so let’s inject a mapper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.malsolo.orika.test.spring; import com.malsolo.orika.test.domain.Person; import ma.glasnost.orika.MapperFacade; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PersonServiceImpl implements PersonService { @Autowired private PersonRepository personRepository; private MapperFacade mapper; @Autowired public void setMapperFactory(MapperFactory mapperFactory) { this.mapper = mapperFactory.getMapperFacade(); } @Override public Person obtainPerson() { return mapper.map(this.personRepository.findPerson(), Person.class); } } |
As you can see, I used setter injection (via autowiring) to provide a MapperFactory in order to obtain from it a MapperFacade. I’m using the suggestion of having the MapperFactory as singleton, that it’s easy to achieve with Spring.
Since MapperFactory has a particular way to be instantiated, the best option is to create a factory for exposing it, a FactoryBean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.malsolo.orika.test.spring; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.DefaultMapperFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; @Component public class MapperFactoryFactory implements FactoryBean<MapperFactory> { @Override public MapperFactory getObject() throws Exception { return new DefaultMapperFactory.Builder().build(); } @Override public Class<?> getObjectType() { return MapperFactory.class; } @Override public boolean isSingleton() { return true; } } |
This approach has been selected just in case I want to use a BoundMapperFacade, but it’s possible to use a MapperFacade directly by creating a MapperFacadeFactory.
Now, let’s configure the Spring application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.malsolo.orika.test.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan public class OrikaSpringTest { public static void main(String... args) { ApplicationContext context = new AnnotationConfigApplicationContext(OrikaSpringTest.class); PersonService personService = context.getBean(PersonService.class); Person person = personService.obtainPerson(); System.out.printf("%s\n", person.toString()); } } |
This is enough for the project to run:
1 |
Person{id=0, name=Name 0, surnames=null, address=null} |
But pay attention, the mapper didn’t work, because there are differences between the two classes (tow attributes with different names, and the same concept, address, with different types)
Plugging in Orika Mappers and Converters with Spring
Orika provides custom converters and mappers, so the only thing we need is to configure them as spring beans in the application context. Let’s see how to do this.
First, we need a custom mapper. We annotate it as component to be discovered (via component scanning) by Spring.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.malsolo.orika.test.spring; import com.malsolo.orika.test.domain.Address; import com.malsolo.orika.test.domain.Person; import com.malsolo.orika.test.dto.PersonDTO; import ma.glasnost.orika.CustomMapper; import ma.glasnost.orika.MappingContext; import org.springframework.stereotype.Component; @Component public class PersonDtoToPersonMapper extends CustomMapper<PersonDTO, Person> { @Override public void mapAtoB(PersonDTO a, Person b, MappingContext context) { b.setId(a.getId()); b.setName(a.getName()); b.setSurnames(a.getLastNames()); //I could use the protected mapperFacade if I need to map a particular field //this.mapperFacade.map(sourceObject, destinationClass); Address address = new Address(); address.setStreet(a.getStreetAddress()); address.setCity(a.getCity()); address.setZipCode(a.getPostalCode()); b.setAddress(address); } @Override public void mapBtoA(Person b, PersonDTO a, MappingContext context) { a.setId(b.getId()); a.setName(b.getName()); a.setLastNames(b.getSurnames()); Address address = b.getAddress(); if (address != null) { a.setStreetAddress(address.getStreet()); a.setCity(address.getCity()); a.setPostalCode(address.getZipCode()); } } } |
Finally, we have to plug in mappers and converters that belongs to the Spring application context, into the MapperFactory. If we extend ConfigurableMapper we will have a MapperFactory created for us, and later on, the chance to access the application context itself to look up for the custom mappers and converters that are Spring components to register them in the MapperFactory.
Let’s show the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package com.malsolo.orika.test.spring; import java.util.Map; import ma.glasnost.orika.Converter; import ma.glasnost.orika.Mapper; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.impl.ConfigurableMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class SpringConfigurableMapper extends ConfigurableMapper { private ApplicationContext applicationContext; private MapperFactory mapperFactory; @Autowired public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; addSpringMappers(); addSpringConverter(); } @Override protected void configure(MapperFactory factory) { super.configure(factory); this.mapperFactory = factory; } private void addSpringMappers() { @SuppressWarnings("rawtypes") final Map<String, Mapper> mappers = applicationContext .getBeansOfType(Mapper.class); for (final Mapper<?, ?> mapper : mappers.values()) { addMapper(mapper); } } private void addMapper(Mapper<?, ?> mapper) { this.mapperFactory.registerMapper(mapper); } private void addSpringConverter() { @SuppressWarnings("rawtypes") final Map<String, Converter> converters = applicationContext .getBeansOfType(Converter.class); for (final Converter<?, ?> converter : converters.values()) { addConverter(converter); } } private void addConverter(Converter<?, ?> converter) { this.mapperFactory.getConverterFactory().registerConverter(converter); } } |
Some important things to note here:
- Our class SpringConfigurableMapper is a @Component
- Our class SpringConfigurableMapper has the ApplicationContext @Autowired
- Our class extends ConfigurableMapper that implements MapperFacade
When Spring instantiates it, it will call its constructor that is inherited from ConfigurableMapper and it calls an init method that creates a MapperFactory and allows you to configure via the overriden method.
So, the first method called is configure(MapperFactory).
Furthermore, don’t create your own MapperFactory as I did above, because it won’t be the one you’ll use to register the mappers and converters, on the contrary, this class will create a new MapperFactory.
It’s the same as if you implement ApplicationContextAware, but I’d rather this approach.
Besides, it implies that the method will be called after all the beans have been created. Since you already have a MapperFactory, you can then search for custom components and converters that are spring beans and register them in the MapperFactory.
So, you have to slightly change the PersonServiceImpl and it’s better to not have a MapperFacadeFactory or you will have an autowiring exception because there would be two beans of the MapperFacade class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.malsolo.orika.test.spring; import ma.glasnost.orika.MapperFacade; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.malsolo.orika.test.domain.Person; @Service public class PersonServiceImpl implements PersonService { @Autowired private PersonRepository personRepository; @Autowired private MapperFacade mapper; @Override public Person obtainPerson() { return mapper.map(this.personRepository.findPerson(), Person.class); } } |
Now, if you run the Orika with Spring main class, OrikaSpringTest, everything will run as expected:
1 |
Person{id=85, name=Name 85, surnames=[S., Surname 85], address=Address{street=My street 85, city=City 85, zipCode=code 85}} |
October 23, 2014 at 17:02
Thanks for this great article !