У меня есть ObjectMapper
, для которого настроено следующее DateTimeFormatter
:
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(ZoneOffset.UTC);
Я хочу преобразовать карту с OffsetDateTime
в json.Моя проблема в том, что, по-видимому, OffsetDateTime
преобразуется правильно, когда это значение
Map<Integer, OffsetDateTime> map = ImmutableMap.of(1, offsetDateTime);
System.out.println(mapper.writeValueAsString(map));
// {"1":"2019-03-20T16:46:00.000+0000"}
, но не когда это ключ
Map<OffsetDateTime, Integer> map = ImmutableMap.of(offsetDateTime, 1);
System.out.println(mapper.writeValueAsString(map).toString());
// {"2019-03-20T16:46Z":1}
Обратите внимание, что секунды и миллисекунды были усечены.Я проверил это с другими картами, такими как HashMap
или TreeMap
, с такими же результатами.
Это определение ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(DateConstants.SIMPLE_DATE_FORMATTER);
mapper.registerModule(new JavaTimeModule());
SimpleModule instantModule = new SimpleModule();
instantModule.addDeserializer(OffsetDateTime.class, new OffsetDateTimeDeserializer());
instantModule.addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
mapper.registerModule(instantModule);
mapper.registerModule(offsetDateTimeModule);
и этого сериализатора:
public class OffsetDateTimeSerializer extends JsonSerializer<OffsetDateTime> {
@Override
public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
String str = DateConstants.FORMATTER.format(value);
gen.writeString(str);
}
}
Редактировать после ответа assylias:
Теперь я изменил свой SimpleModule
на
SimpleModule instantModule = new SimpleModule();
instantModule.addDeserializer(OffsetDateTime.class, new OffsetDateTimeDeserializer());
instantModule.addKeyDeserializer(OffsetDateTime.class, new OffsetDateTimeKeyDeserializer());
instantModule.addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
instantModule.addKeySerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
mapper.registerModule(instantModule);
с OffsetDateTimeKeyDeserialzer
как
public class OffsetDateTimeKeyDeserializer extends KeyDeserializer {
@Override
public OffsetDateTime deserializeKey(String key, DeserializationContext ctxt) {
return OffsetDateTime.from(DateConstants.FORMATTER.parse(key));
}
}
Когда значение OffsetDateTime
, все продолжает работать правильно.Однако, если это ключ, я теперь получаю
Exception in thread "main" com.fasterxml.jackson.core.JsonGenerationException: Can not write a string, expecting field name (context: Object)
at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1961)
at com.fasterxml.jackson.core.json.JsonGeneratorImpl._reportCantWriteValueExpectName(JsonGeneratorImpl.java:244)
at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._verifyValueWrite(WriterBasedJsonGenerator.java:866)
at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeString(WriterBasedJsonGenerator.java:368)
at com.brandwatch.signals.commons.util.jackson.OffsetDateTimeSerializer.serialize(OffsetDateTimeSerializer.java:16)
at com.brandwatch.signals.commons.util.jackson.OffsetDateTimeSerializer.serialize(OffsetDateTimeSerializer.java:12)
at com.fasterxml.jackson.databind.ser.std.StdKeySerializers$Dynamic.serialize(StdKeySerializers.java:225)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:707)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:639)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219)
Редактировать 2:
Этот KeySerializer
, кажется, сделал трюк для меня:
public class OffsetDateTimeKeySerializer extends StdSerializer<Object> {
public OffsetDateTimeKeySerializer() {
super(Object.class);
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
if (value instanceof OffsetDateTime) {
String str = DateConstants.FORMATTER.format((OffsetDateTime) value);
gen.writeFieldName(str);
} else {
gen.writeFieldName(value.toString());
}
}
}