Search code examples
javadatecalendardozer

Mapping XMLGregorianCalendar to Calendar with Dozer


Prerequisites

Dozer 5.5.1

Code

    public class Testdata {

            public static final Calendar CALENDAR_EXPECTATION;
            public static final XMLGregorianCalendar XMLGREGORIANCALENDAR_INPUT;

            static {
                    CALENDAR_EXPECTATION = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"), Locale.GERMANY);
                    CALENDAR_EXPECTATION.clear();
                    CALENDAR_EXPECTATION.set(2015, 1, 2, 13, 15, 22);

                    XMLGREGORIANCALENDAR_INPUT = XMLGregorianCalendarImpl.createDateTime(2015,
                                                                                            1,
                                                                                            2,
                                                                                            13,
                                                                                            15,
                                                                                            22,
                                                                                            0,
                                                                                            (CALENDAR_EXPECTATION.get(Calendar.ZONE_OFFSET)
                                                                                            + CALENDAR_EXPECTATION.get(Calendar.DST_OFFSET))
                                                                                            / (60 * 1000));
            }
    }


    public class MappingTest {

            @Autowired
            private org.dozer.DozerBeanMapper dozerBeanMapper;

            private static x.y.z.ClassToMap classToMap;

            @BeforeClass
            public static void setupModel() throws Exception {
                    classToMap = new ClassToMap(Testdata.XMLGREGORIANCALENDAR_INPUT);
            }

            @Test
            public void testTransaktionsInfoToTransaktionsInfo(){
                    final x.y.MyMappedClass mapped =
                            dozerBeanMapper.map(classToMap, x.y.MyMappedClass.class);

                    compareCalendar(mapped.getMyCalendar(), Testdata.CALENDAR_EXPECTATION);
            }

            private void compareCalendar(Calendar ergebnis, Calendar erwartung) {
                    assertThat(ergebnis, notNullValue());
                    assertThat(ergebnis.get(Calendar.YEAR), is(erwartung.get(Calendar.YEAR)));
                    assertThat(ergebnis.get(Calendar.MONTH), is(erwartung.get(Calendar.MONTH)));
                    assertThat(ergebnis.get(Calendar.DAY_OF_MONTH), is(erwartung.get(Calendar.DAY_OF_MONTH)));
                    assertThat(ergebnis.get(Calendar.HOUR), is(erwartung.get(Calendar.HOUR)));
                    assertThat(ergebnis.get(Calendar.MINUTE), is(erwartung.get(Calendar.MINUTE)));
                    assertThat(ergebnis.get(Calendar.SECOND), is(erwartung.get(Calendar.SECOND)));
                    assertThat(ergebnis.get(Calendar.MILLISECOND), is(erwartung.get(Calendar.MILLISECOND)));
                    assertThat(ergebnis.getTimeZone(), is(erwartung.getTimeZone()));
            }
    }

Problem

The assert assertThat(ergebnis.get(Calendar.MONTH), is(erwartung.get(Calendar.MONTH))); fails. The problem ist that the month in expectation is correct (1) but the mapped Calendar containts (0).

In org.dozer.converters.CalendarConverter following happens:

...
} else if (XMLGregorianCalendar.class.isAssignableFrom(srcFieldClass)) {
  Calendar c = ((XMLGregorianCalendar) srcObj).toGregorianCalendar();
  result.setTime(c.getTime());
  result.setTimeZone(c.getTimeZone());
}
...

Calendar c contains the wrong month (= 0). And the result after call result.setTime(c.getTime()); contains also month = 0.

Should I write my own converter to solve this? And how to solve the problem?

Thanks in advance.

Regards,

Max


Solution

  • For XMLGregorianCalendar, January corresponds to 1 and December corresponds to 12, your test is OK so far:

    month: 1 to 12 or DatatypeConstants.FIELD_UNDEFINED

    However, Calendar has zero-based months, meaning that January corresponds to 0 and December corresponds to 11.

    The first month of the year in the Gregorian and Julian calendars is JANUARY which is 0; the last depends on the number of months in a year.

    In other words, your assertion is wrong. You are creating an XMLGregorianCalendar which has month January, and an assertion where you assume that it is February. The convert method in Dozer looks correct.

    What you should do is to use the constants that Calendar provides, which makes it irrelevant whether the count starts with 0 or 1:

    CALENDAR_EXPECTATION = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"), Locale.GERMANY);
    CALENDAR_EXPECTATION.clear();
    CALENDAR_EXPECTATION.set(2015, Calendar.JANUARY, 2, 13, 15, 22);