java - 为什么 ObjectMapper 将 Date 类型更改为 Long
问题描述
我正在尝试使用 Jackson ObjectMapper 从对象中获取地图:
ObjectMapper oMapper = ObjectMapperWithDate.getObjectMapper();
Map<String, Object> map = oMapper.convertValue(obj, Map.class);
我对日期字段有疑问,因为在地图中它们正在变成长对象。
我添加了反序列化器,如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;
}
}
}
}
当然,对映射器的调用看起来有点不同:
ObjectMapper oMapper = ObjectMapperWithDate.getObjectMapper();
Map<String, Object> map = oMapper.convertValue(obj, Map.class);
现在 Date 对象成为地图中的 String 对象。在其中正确表示日期。但我需要它们保持为 Date 类型。有趣的是,如果我在反序列化器中设置断点,则永远无法到达。因此,我认为永远无法到达反序列化器,这是因为序列化后的映射器根据 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 将 Date 设为 String 或 Long,并且在反序列化时永远不会识别 Date。
映射后如何让 Date 属性保持 Date 属性?我需要他们被认可。
顺便说一句,BigDecimal 属性变成了 Double 属性。这似乎是类似的问题,但这两种类型对我进一步的工作没有太大的区别。
解决方案
因为您将 map 的值类型定义为Object
,所以 Jackson 不会选择您的自定义反序列化器类型Date
,而是使用其默认反序列化器将所有类型转换为基本类型(如 long、String、LinkedHashMap 等)。
如果您的对象中只有Date
字段,则可以更改convertValue
方法的第二个参数:
Map<String, Date> map = oMapper.convertValue(obj, new TypeReference<Map<String, Date>>() {});
但显然这不是您的情况,因此对于具有不同类型字段的对象,最直接的方法是将您的反序列化器类型更改为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;
}
}
}
另外,不要忘记用.addDeserializer
with替换第一个参数Object.class
有关更奇特的方法,请查看这篇文章:http ://robertmarkbramprogrammer.blogspot.com/2018/05/de-serialise-json-string-to-map-with.html
推荐阅读
- wordpress - WordPress MU 域映射重定向循环
- php - 如何使用计算日期在 MySQL 中一次更新多行
- python - Networkx中大型网络的可视化问题
- flutter - 我怎样才能将容器向右移动
- mule - Anypoint Platform - 使用 Autodiscovery ID 将 API Manager 与 Cloudhub 应用程序连接起来
- javascript - 到达某个位置时如何激活间隔?
- laravel - Laravel 如果条件匹配禁用,否则不要禁用
- javascript - 是否可以显示
- reactjs - 页面刷新/视图更改后如何防止 React 中的状态更改?
- php - 如何从传入的 url 中获取 Id 值?