Friday, January 31, 2014

AutoMapper for Java

In a nutshell ordinary web service takes entities from datasource (our domain model) and transforms them into DTO objects (our view models) or vise versa. This is quite popular approach becase it allows evolving domain and view models separately. Also it is neutral because one entity might have more than one narrow view models depending on needs. This is direct way to CQRS approach where read and write models are different at least for consumer's perspective.

 I do not consider another approach here where domain entities are intended to be mapped directly into json or xml. It is inextensible and ugly from my perspective however is quite attractive and simple.

Well, as mentioned I prefer the first approach, and if you had used it as well  then you definetly had to face with developing convertors layer. This is the most annoying and dissapointing part and place where bugs live in prosperity.

Since .NET I liked well-known library AutoMapper, it is lightweight smart convertor which allows transparent and codeless converting between domain and view models. For many cases it was Holy Grail.
I expected similar lib for Java as well and yes found it:  ModelMapper.

Consider this  example:

class User { 
  String firstName;
  String email;
  String creditCard;
}
 
class UserDTO{  
  String firstName;
  String email;
}

And lets consider how it might be transformed:
User user = ...
ModelMapper modelMapper = new ModelMapper();
UserDTO userDTO = modelMapper.map(user, UserDTO.class);


Thinking it is trivial? Well, how about this?
class User {
  Date burthday;
  String firstName;
  Address address;
}
class Address {
  String country;
  String street;
}
 
class UserDTO{
  long burthday;
  String firstName;
  String addressStreet;
}

And solution:
Converter<Date, Long> timeConvertor = new AbstractConverter<Date, Long>() {
  protected Long convert(Date dt) {
    return dt.getTime();
  }
};
 
ModelMapper modelMapper = new ModelMapper();
 
modelMapper.addConverter(timeConvertor);
 
UserDTO userDTO = modelMapper.map(user, UserDTO.class);

Going further this library is smart enough to care about ambiguity, skipping, diffrent naming strategies, mapping in advance and so on.

Well the library is attractive, however there is no magic and reflection is used there, so be aware.


No comments: