简体   繁体   English

为什么 ObjectMapper 将 Date 类型更改为 Long

[英]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.

相关问题 ObjectMapper将日期更改为字符串 - ObjectMapper changes Date to String Jackson ObjectMapper 将本地日期序列化为长字符串 - Jackson ObjectMapper serializing local date into a long striing 为什么 Jackson ObjectMapper 给我这个错误,将 JSON 字段转换为日期 object? 无法从字符串反序列化 java.util.Date 类型的值 - Why Jackson ObjectMapper give me this error converting JSON field into a Date object? Can not deserialize value of type java.util.Date from String 如何使 fasterXml ObjectMapper 将格式属性放入 long 类型字段的模式中 - How can I make fasterXml ObjectMapper put a format property into schema for fields of the type long ObjectMapper 无法解析为类型 - ObjectMapper cannot be resolved to a type ObjectMapper writeValueAsString更改字节缓冲区pos - ObjectMapper writeValueAsString changes bytebuffer pos Jackson ObjectMapper 的日期和时间戳序列化 - Date and Timestamp serialization by Jackson ObjectMapper Map 使用 ObjectMapper 到不同的类型 - Map to a different type using ObjectMapper 我不知道为什么不能自动装配。 未找到“ObjectMapper”类型的 bean。 (注释错误) - I don't konw Why Could not autowire. No beans of 'ObjectMapper' type found. (Annotation Error) Android / Java将String日期转换为long类型 - Android / Java convert String date to long type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM