Friday, December 19, 2008

Dozer Custom Converter for Joda DateTime

I mentioned in my last post how excited I was to try out Dozer. Today I got the chance to play around with it a little bit. As a proof-of-concept for myself, I wrote a custom converter to handle mapping of Joda-Time DateTime's to and from Java Calendars. I thought that this should be very easy, and I was happy to find out that it was. The first step was to actually implement the CustomConverter interface:
package com.scottmcmaster365.dozerdemo;

import java.util.Calendar;

import net.sf.dozer.util.mapping.MappingException;
import net.sf.dozer.util.mapping.converters.CustomConverter;

import org.joda.time.DateTime;

/**
* Custom converter for Joda DateTime's.
* @author Scott McMaster
* http://www.scotmcmaster365.com/
*
*/
public class DateTimeConverter implements CustomConverter {

 @SuppressWarnings("unchecked")
 @Override
 public Object convert(Object existingDestinationFieldValue,
   Object sourceFieldValue, Class destinationClass, Class sourceClass)
 {
  if( sourceFieldValue == null )
  {
   return null;
  }
  
  if( sourceFieldValue instanceof Calendar )
  {
   // Note that DateTime is immutable, so
   // we can't do much with the existingDestinationFieldValue.
   return new DateTime(sourceFieldValue);
  }
  else if( sourceFieldValue instanceof DateTime )
  {
   Calendar result;
   if( existingDestinationFieldValue == null )
   {
    result = Calendar.getInstance();
   }
   else
   {
    result = (Calendar) existingDestinationFieldValue;
   }
   result.setTimeInMillis(((DateTime) sourceFieldValue).getMillis());
   return result;
  }
  
  throw new MappingException("Misconfigured/unsupported mapping");
 }

}

The logic here is very straightforward, although you could imagine creating many more Dozer converters for DateTime's. (One that accepts a formatted String comes immediately to mind.) You can wire this up with a little bit of XML as so: Here are a couple of unit tests that demonstrate the capability. Not shown are a couple of little classes, TypeWithCalendar and TypeWithDateTime, which have bean properties called "value" of type java.util.Calendar and org.joda.DateTime, respectively.
/**
 * Test mapping from Calendar <-> DateTime
 * using Dozer.
 * @author Scott McMaster
 *
 */
public class TestDozerDateTimeConverter
{
 private DozerBeanMapper mapper;

 @Before
 public void setUp()
 {
  List mappingFiles = new ArrayList();
  mappingFiles.add("dozermappings.xml");
  mapper = new DozerBeanMapper();
  mapper.setMappingFiles(mappingFiles);
 }
 
 @Test
 public void testToCalendarType()
 {
  DateTime then = new DateTime(1995, 11, 27, 0, 0, 0, 0);
  TypeWithDateTime joda = new TypeWithDateTime();
  joda.setValue(then);
  
  TypeWithCalendar calendar = 
    (TypeWithCalendar) mapper.map(joda, TypeWithCalendar.class);
  
  assertEquals((Long) then.getMillis(), (Long) calendar.getValue().getTimeInMillis());
 }
 
 @Test
 public void toJodaType()
 {
  Calendar then = Calendar.getInstance();
  then.set(1995, 10, 27);
  TypeWithCalendar calendar = new TypeWithCalendar();
  calendar.setValue(then);
  
  TypeWithDateTime joda =
   (TypeWithDateTime) mapper.map(calendar, TypeWithDateTime.class);
  
  assertEquals((Long) then.getTimeInMillis(), (Long) joda.getValue().getMillis());
 }
}

1 comment:

itchyknee said...

Hi Scott,
are you making this code available to use? Does a licence apply?
Thanks
Pat