// you’re reading...

Development

GXT/GWT, DTOs and Dozer : Managing the Exception rather then the Common Case

For all of its amazing cleverness, GWT has one really difficult area, persistence. There are various projects and attempts to clear this are up but most are very young and have a ways to go. This gets even more complicated if your not, lets face it, using Hibernate. As a Cayenne fan I don’t use Hibernate so of course my path is even more complex then most. Persistent objects, in most popular frameworks, carry with them a lot of persistent baggage that doesn’t cleanly serialize across the wire.

Thankfully there is, as with most things software related, a pattern! The pattern in this case is to use a Data Transfer Object (DTO). A DTO is basically a serializable bean that mirrors the persistent object. This is an annoying duplication of work and obviously violates the DRY (Don’t Repeat Yourself) principle since you are essentially cloning the Persistent object as a basic java bean. The upside of it is that you can control exactly what gets into your DTO (and thus what is transferred to the client). Originally I was constructing these beans as required, doing a pretty ad hoc job of it and generally causing myself headaches.

My first attempt at streamlining this was to use the BeanUtils apache commons project. This library has some simple methods for copying properties between beans which, in the end, is what the DTO is all about. This worked well for common and primitive types that were shared (name and type) between the two objects but it fell over pretty quickly if the types mismatched. Additionally, there is no easy way to exclude or customize an individual field level map and no way to do one-way mappings (there is never a reason to map the ID from the Bean to the Persistent Object!)

What are my requirements and why didn’t BeanUtils not working?

  • BeanUtils is exceptions based: If it has a mismatched attribute it blows up spectacularly and you then have to treat those objects differently.
  • BeanUtils doesn’t have an exceptions mechanism: In my situation where I have enumerations everywhere this meant that many objects of mine are not eligible for BeanUtils. (GWT doesn’t easily support enumerations so I have to convert them to int before sticking the int in the DTO with a map of values)
  • BeanUtils doesn’t have an extensions mechanism: Once your object is out of the path of automation there is no way back, its a manual coding exercise.

There was a better way: Dozer

I had looked at Dozer a few times and it just seemed Scary and Large but in my desperation I started to dig around and discovered how addictingly easy it is to start with Dozer:

public static void setUser(UserBean bean, Pguser user){
     Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
     mapper.map(bean,user);
}

This is your base ‘BeanUtils replacement’ usage of Dozer. In my case this is part of a larger static class that is a big BeanFactory, eg: A bit file that has a bunch of static methods for converting beans to objects and objects to beans.

Fantastic! Now my conversions did not blow up in the general case where one object had a field that the other one lacked. However, it still exploded when types mismatched. Thats where the Dozer mapping comes in. Dozer allows you to create an XML file of exceptions that run as a part of the map(a,b) process. You don’t have to specific ALL fields in this mapping, just the differentials! Once I understood that it was happy-pants-time!

All you do is toss a file called ‘dozerBeanMapping.xml’ into your class path and Dozer automatically picks it up. No muss no fuss. Lets look at one of my beans in this file. In the below example I am basically excluded my enumerations from the mapping process. Note: you can do a LOT more then this, my goal here is to show how easy it is to use Dozer to manage your bean<->object exceptions.

<mapping>
   <class-a>com.pgi.common.Clientsettings</class-a>
   <class-b>com.pgi.webapp.client.dto.ClientsettingsBean</class-b>
   <field-exclude>
      <a>jobmode</a>
     <b>jobmode</b>
   </field-exclude>
   <field-exclude>
      <a>removemethod</a>
      <b>removemethod</b>
   </field-exclude>
   <field-exclude>
      <a>reportingmode</a>
      <b>reportingmode</b>
   </field-exclude>
</mapping>

But now how do I put my enumerations into my DTO? Two options really

For now I am putting this mapping in my factory method post auto-map

public static ClientsettingsBean getClientsettingsBean(Clientsettings settings){
   Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
   ClientsettingsBean theBean = mapper.map(settings,ClientsettingsBean.class);
   theBean.setJobmode(settings.getJobmode().ordinal());
   theBean.setReportingmode(settings.getReportingmode().ordinal());
   theBean.setRemovemethod(settings.getRemovemethod().ordinal());
   theBean.setId(DataObjectUtils.intPKForObject(settings));
   return theBean;
}
There is another way though, I can create a custom Dozer Converter that knows how to do this mapping for me. I am still working on this though, Enumerations in my case are tough as I have about 15 of them and they all have a custom methods that goes from int to enum. Since I don’t want 15 converters that do the same thing, just with a different class, I need to find a way to extend my enumeration from a base class that has this mapping.
With a base enumeration class (if possible, haven’t looked deeply yet) I can have one Dozer Conversion class that maps back and forth between any of my enumerations and the class that has that enumeration as an attribute. Should be fun.
An intriguing idea for the future would be a Cayenne template that auto-creates these DTOs, Factory and Mapping files for me as part of the Cayenne class generation process. I’d still need to copy them manually into my GWT *.client.* namespace but it would speed things up considerably.

Discussion

No comments for “GXT/GWT, DTOs and Dozer : Managing the Exception rather then the Common Case”

Post a comment