使用 Dozer 将 XMLGregorianCalendar 映射到日历

Mapping XMLGregorianCalendar to Calendar with Dozer

先决条件

推土机 5.5.1

代码

    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()));
            }
    }

问题

断言 assertThat(ergebnis.get(Calendar.MONTH), is(erwartung.get(Calendar.MONTH))); 失败。 问题是预期的月份是正确的 (1),但映射的日历包含 (0)。

在 org.dozer.converters.CalendarConverter 中发生以下情况:

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

日历 c 包含错误的月份 (= 0)。 调用后的结果 result.setTime(c.getTime());还包含 month = 0.

我应该自己写一个转换器来解决这个问题吗? 以及如何解决问题?

提前致谢。

此致,

最大

XMLGregorianCalendar1月对应112月对应12,目前您的测试还可以:

month: 1 to 12 or DatatypeConstants.FIELD_UNDEFINED

但是,Calendar 有从零开始的月份,这意味着 January 对应于 0 12月对应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.

也就是说,你的说法是错误的。您正在创建一个 XMLGregorianCalendar,其中月份为 January,并且您假设它是 February 的断言。 Dozer 中的转换方法看起来是正确的。

你应该做的是使用Calendar提供的constants,这使得计数是否以0或[=29开头无关紧要=]1:

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