Data Transfer/Value Objects and Entity/Domain object mapping with Hibernate

I know that a lot of people, especially the hibernate developers, say that you can use hibernate entity or domain objects as data transfer (dto) or value object (vo) when transfering data between layers of your application. In my experience this seldom works as you are bound to get lazy load exceptions (LazyInitializationException) at some point. Exchanges about how to handle dtos/vos can get quiet heated on the hibernate forums and personally I canŽt understand why they are so adament about their šuser hibernate entity beansš approach.

Value Objects to Entity/Domain Objects and back again

There is nothing more frustrating than trying to access a property only to be told that it canÂŽt be loaded. The situation gets worse if you use reflection and the object you get is not the object you expect because it has been wrapped in a proxy. Of course you can switch off lazy loading in different ways but this basically circumvents the whole purpose of lazy loading in the first place. To make sure that objects are properly intialized before being sent across layers I like to use the data transfer/value object pattern.

Using this pattern means that

  • you only pass the data needed by the other layer, (value objects need not map every property of the entity/domain object and may be more course grained eg one class for person and address instead of two.)
  • front-end developers or other layers won't get any nasty surprises,
  • that you intialise all your required properties before leaving the data or service layer, and
  • implementation details are hidden from other layers who don't need to know what ORM technology you are using.

Object mapping/copying frameworks

For a long time I used to use Apaches BeanUtils to help with copying entity to value object and visa-versa. The problem with BeanUtils is that it doesnÂŽt handle nested properties nicely if they are of different types. E.G. A nested PersonVO may contain a nested AddressVO, while the entity object is a Person with an Address object. I know some people use digester here but its a lot of work.

I looked around for a general framework for copying entity to value objects and back and found serveral projects but they all seemed dormant. These projects included: (I canÂŽt remember all that I looked at)

  1. OTOM
  2. andXSnapshot

In the end I went back to BeanUtils and had given up hope to find a simple but comprehensive DTO/Entity mapping framework. Then one day I stumbled upon dozer.

The solution is Dozer!

Dozer is simple to use and easy to configure. Why this projectÂŽs profile is not higher I donÂŽt know. Copying objects is easy as

dozer.map(src,dst);

This will work where the property names of the source class match the property names of the destination class. No extra mapping is required. You can have more course grained destination classes by leaving out unnecessary properties in the class definition. If you want to map two classes to one class you can defined more complex mappings uisng XML files. A simple class wrapper would look something like

public class ConversionServiceImpl implements ConversionService{

private static Log logger = LogFactory.getLog(ConversionServiceImpl.class);
private DozerBeanMapper dozer;

public Object convertObject(Object src, Object dest) {
dozer.map(src, dest);
return dest;
}

public Collection convertCollection(Collection src, Collection dest, Class destClass) {
if (src==null || dest==null) {
logger.error("Either the source or destination object was null");
dest=null;
return dest;
}
for (Object obj : src){
try {
Object destObj = destClass.newInstance();
convertFromTo(obj, destObj);
dest.add(destObj);
} catch (InstantiationException e1) {
logger.error("Instantion exception.");
logger.error(Utils.convertStackTraceToString(e1));
} catch (IllegalAccessException e1) {
logger.error("Illegal access exception.");
logger.error(Utils.convertStackTraceToString(e1));
}
}
return dest;
}

public DozerBeanMapper getDozer() {
return dozer;
}

public void setDozer(DozerBeanMapper dozer) {
this.dozer = dozer;
}

}

Although the above is a simple example it shows the power of dozer. More complex mapping can be done using xml files. There is more info on the dozer site . I am sure there is a way for dozer to hanlde collection without the hack used above but I need to read some more documentation :(

Comments