неправильный часовой пояс с часами и Джексоном

#java #datetime #jackson

#java #дата и время #джексон

Вопрос:

Я использую jackson для де- / сериализации dto. Я сделал некоторую пользовательскую конфигурацию для jacksons ObjectMapper и Clock , как показано в следующем коде:

 @Bean
public ObjectMapper objectMapper()
{
    ObjectMapper mapper = new ObjectMapper();

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
    mapper.setDateFormat(dateFormat);

    return mapper;
}

@Bean
@Profile("!testing")
public Clock clock()
{
    return Clock.systemDefaultZone();
}
 

Для тестирования я определил свои пользовательские часы (SettableClock):

 @Bean
@Profile("testing")
public Clock clock()
{
    return new SettableClock(); // extends Clock
}
 

В моей базе данных я храню некоторые даты в следующем формате: yyyy-MM-dd HH:mm:ss .

Когда я создаю новую запись в базе данных, я получаю следующий результат:
1 | 2016-10-16 18:42:55 (немецкое время, UTC 2), что правильно.

Эта дата будет создана мгновенно, используя определенные часы:

 Instant now = Instant.now(clock);
return new Timestamp(now.toEpochMilli());
 

Теперь моя проблема в том, что Джексон неправильно преобразует дату, а не так, как определено в конфигурации object mapper. Например. 2016-10-16T16:42:55Z который не является UTC 2..

Я обнаружил эту проблему при написании теста, потому что в моем тесте, когда я создаю новый Instant с помощью Instant.now(), я получаю время от UTC 2 (по местному времени). Тот же результат при использовании new Date() в js, например.

Насколько я понимаю документацию Джексона, моя конфигурация object mapper кажется действительной. Но почему Джексон не использует его? В режиме отладки я вижу, что моя конфигурация будет применена.

Этот код показывает, как я включаю настроенный преобразователь объектов:

 @Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
{
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
    {
        MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
        jacksonConverter.setObjectMapper(objectMapper);
        converters.add(jacksonConverter);

        super.configureMessageConverters(converters);
    }
}
 

Кто-нибудь знает, почему я все еще получаю неправильный часовой пояс?
При сериализации даты с использованием 02:00 все работает так, как ожидалось. Просто десериализация не работает : (

Я также пытался настроить часы специально для создания времени в UTC 2, но это ничего не меняет. Я думаю, проблема, похоже, находится в моем картографе объектов…

С уважением, Тим

Комментарии:

1. Instant является нейтральным часовым поясом (по сути, всегда в UTC), что может быть частью проблемы. Использование Instant также подразумевает, что вы регистрируете что-то (исторические данные), которые должны храниться в UTC. Исходные классы форматирования даты и времени не являются потокобезопасными, вам нужен новый для каждого потока. Можно ли использовать классы java.time полностью? Далее, всякий раз, когда вы сохраняете значение даты и времени, вам также необходимо сохранить часовой пояс, иначе двусмысленность может повредить вам позже.

2. Спасибо за ваш ответ. Что касается даты базы данных: я использую postgresql с TIMESTAMPTZ (с часовым поясом), поэтому я всегда получаю дату с соответствующим часовым поясом. Использование java.time везде было бы здорово, но даже когда я добавляю `mapper.configure(SerializationFeature. WRITE_DATES_AS_TIMESTAMPS, false);` для моей конфигурации object mapper Instant будет сериализован как временная метка, что определенно не то, что я хочу. Имхо, написание клиентского сериализатора для мгновений — неправильный путь, потому что Джексон уже предоставляет эти опции из коробки, но для java.util. Дата..

3. попробуйте добавить @EnableWebMvc

4. @danidacar ничего не меняет 🙁 . Поскольку я использую spring boot, EnableWebMvc вообще не является обязательным, верно?

5. попробуйте использовать WebMvcConfigurationSupport, как здесь dzone.com/articles/customizing