[英]Why ObjectMapper changes Date type into Long
I am trying to get a map from the object using Jackson ObjectMapper:我正在尝试使用 Jackson ObjectMapper 从对象获取地图:
ObjectMapper oMapper = ObjectMapperWithDate.getObjectMapper();
Map<String, Object> map = oMapper.convertValue(obj, Map.class);
I have problems with Date fields, for in the map they are becoming Long objects.我有日期字段的问题,因为在地图中它们变成了 Long 对象。
I have added de/serializers, as in ObjectMapper changes Date to String我添加了反序列化程序,如ObjectMapper 将日期更改为字符串
public class ObjectMapperWithDate {
@Bean
public static ObjectMapper getObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.registerModule(
new SimpleModule("foo")
.addDeserializer(Date.class, new DateDeserializer())
.addSerializer(Date.class, new DateSerializer())
);
return mapper;
}
public static class DateSerializer extends StdScalarSerializer<Date> {
public DateSerializer() {
super(Date.class);
}
@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
String output = formatter.format(value);
gen.writeString(output);
}
}
public static class DateDeserializer extends StdScalarDeserializer<Date> {
public DateDeserializer() {
super(Date.class);
}
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
try {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
return formatter.parse(p.getValueAsString());
} catch (Exception e) {
return null;
}
}
}
}
Of course, the call for the mapper looks a bit different:当然,对映射器的调用看起来有点不同:
ObjectMapper oMapper = ObjectMapperWithDate.getObjectMapper();
Map<String, Object> map = oMapper.convertValue(obj, Map.class);
Now the Date objects become String object in the map.现在 Date 对象变成了地图中的 String 对象。 With the dates properly represented in them.
在其中正确表示日期。 But I need them to remain to be of the Date type.
但我需要它们保持为 Date 类型。 What is interesting, if I put breakpoints in the deserialiser, it is never reached.
有趣的是,如果我在反序列化器中放置断点,它永远不会到达。 So, the deserializer is never reached, I think, it is because the mapper after serializing makes Date a String or a Long, depending on SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, and never recognizes the Date's in the time of deserialization.
所以,反序列化器永远不会到达,我认为,这是因为序列化后的映射器根据 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 使 Date 成为 String 或 Long,并且在反序列化时从不识别日期。
How can I let Date properties remain Date ones after mapping?映射后如何让 Date 属性保持 Date 属性? I need them to be recognized.
我需要他们被认可。
BTW, the BigDecimal properties are turned into Double ones.顺便说一句,BigDecimal 属性变成了 Double 属性。 It seems to be the similar problem, but these two types are not of much difference to my further work.
似乎是类似的问题,但这两种类型对我进一步的工作没有太大区别。
Because you defined map's type of values as Object
, Jackson doesn't select your custom deserializer of type Date
and uses its default deserializer where it converts all types to basic ones (like long, String, LinkedHashMap etc.).因为您将地图的值类型定义为
Object
,Jackson 不会选择Date
类型的自定义反序列化器,而是使用其默认反序列化器将所有类型转换为基本类型(如 long、String、LinkedHashMap 等)。
If you only had Date
fields in your object, you could just change the 2nd argument of convertValue
method:如果对象中只有
Date
字段,则只需更改convertValue
方法的第二个参数:
Map<String, Date> map = oMapper.convertValue(obj, new TypeReference<Map<String, Date>>() {});
But obviously it's not your case, so the most straightforward way to do it for an object with different types of fields is to change your deserializer type to Object
and parse all data inside it manually:但显然这不是您的情况,因此对于具有不同类型字段的对象执行此操作的最直接方法是将您的反序列化器类型更改为
Object
并手动解析其中的所有数据:
public static class DateDeserializer extends StdScalarDeserializer<Object> {
public DateDeserializer() {
super(Object.class);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
String valueAsString = p.getValueAsString();
try {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
return formatter.parse(valueAsString);
} catch (Exception e) {
//you could add extra logic to parse other types
return valueAsString;
}
}
}
Also, don't forget to replace the 1st argument of .addDeserializer
with Object.class
另外,不要忘记用
Object.class
替换.addDeserializer
的第一个参数
For more exotic ways to do it, please check this article: http://robertmarkbramprogrammer.blogspot.com/2018/05/de-serialise-json-string-to-map-with.html有关更多奇特的方法,请查看这篇文章: http : //robertmarkbramprogrammer.blogspot.com/2018/05/de-serialise-json-string-to-map-with.html
You should use a POJO to represent your data, instead of a Map
.您应该使用 POJO 来表示您的数据,而不是
Map
。 Since a Map
is ambiguous key-value pairs, there's no type information for each field and Jackson will read values without making any inferences about their type information.由于
Map
是不明确的键值对,因此每个字段都没有类型信息,Jackson 将读取值而不对其类型信息进行任何推断。 By modeling your data in a defined structure, Jackson will read values into the defined types.通过在定义的结构中对数据进行建模,Jackson 会将值读入定义的类型。
public class DataTransferObject
{
Date date;
BigDecimal decimal;
public Date getDate ()
{
return date;
}
public void setDate ( Date date )
{
this.date = date;
}
public BigDecimal getDecimal ()
{
return decimal;
}
public void setDecimal ( BigDecimal decimal )
{
this.decimal = decimal;
}
}
objectMapper.convertValue(obj, DataTransferObject.class);
With this approach, you may use Jackson's serialization features to convert dates using strings or integers.通过这种方法,您可以使用 Jackson 的序列化功能来转换使用字符串或整数的日期。 A custom (de)serializer isn't necessary.
不需要自定义(反)序列化程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.