#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