Wednesday, June 2, 2010

Fast and easy java bean mapping

Java Bean mapping is essential part of many applications. Mapping is often used to serialize Hibernate/JPA/JDO objects, to filter data, to save space/bandwidth when full object data is not needed.
When you are working on GWT application there are two common ways of mapping domain objects between front-end and back-end. One of them is to use same class on both client and server side and use some framework like Gilead to maintain session-related state of object.
Another way is to use data transfer objects on client side. Advantage of such approach are reduced bandwidth usage (you can transfer only data that you are really need in current operation and do not transfer unrelated to current operation data), increased security (you can expose only fields that are really needed to current operation), reduced memory footprint (no need to save session state data on server).
Popular bean mapping frameworks are including Dozer or Apache BeanUtils but all of these frameworks are intensively using reflections to perform mapping operations. Such approach is much slower than mapping performed "by hands", e.g. when you write code like this one:
EntityDto dto = new EntityDto();
dto.setId(entity.getId());
dto.setName(entity.getName());
...
I need solution that works as fast as "by hands" mapping but i am too lazy to write hundreds of lines of routine mapping code.
So i've started small project that generates mapping classes that are as fast as hand-written ones.
Project is located at Google Code: Bean Mapper and it is very easy to use.
To use it you should perform 3 easy steps:
  1. Define mapper interface and annotate methods that should be generated with @Mapper annotation:
    public interface EntityMapper {
       @Mapper
        List<DestinationEntity> map(List<SourceEntity> source);
    }
  2. Obtain implementation of mapper class through factory:
    EntityMapper mapper = (EntityMapper) MapperFactory.getInstance(EntityMapper.class);
    
  3. Use your mapper class:
    List<DestinationEntity> = mapper.map(someSource);
    

Methods that are being generated are as fast as hand-coded. For example if you have 2 classes like these:
public class ClassA {
    int fileld1;
    boolean field2;
    String field3;
    List<ClassA> children;
    //getters and setters
}
public class ClassA {
    String fileld1;
    String field2;
    String field3;
    List<ClassB> children;
    //getters and setters
}
the code being generated for mapping ClassA -> ClassB will look like this:
public ClassB map(ClassA param) {
    ClassB target = new ClassB();
    target.setField1(String.valueOf(param.getField1()));
    target.setField2(String.valueOf(param.getField2()));
    target.setField1(param.getField3());
    if (param.getChildren() != null) {
        target.setChildren(new ArrayList());
        for (ClassA child : param.getChildren()) {
            target.getChildren().add(map(child));
        }
    }
    return target;
}
Actually there will be little more code to properly handle null values, loop dependencies etc. but it will be code that is not using any Reflections overhead and it works several times faster than dynamic mapping frameworks. In some cases it works 100-200 times faster.

Project development is frozen for some time now but it looks stable and I am using it on some of my home projects without any problems.