杰克逊java.util.Date值在Map <string,object =“”>(de-)序列化中

时间:2018-03-15 14:26:12

标签: java jackson jackson-databind

考虑这个属性

@JsonProperty
private Map<String, Object> myMap;

如果将包含的java.util.Date值序列化为long,则不会再次将其反序列化为Date,因为Map<String, Object>中不存在类型信息。我该如何绕过这个问题?我阅读了关于this question的答案,这将是一个解决方法但是没有办法区分包含日期的字符串和在地图中序列化为字符串的日期。 我可以告诉杰克逊为每个地图值包含类型信息,以便杰克逊能够正确地反序列化它们吗?

2 个答案:

答案 0 :(得分:3)

实施自定义反序列化器并将注释@JsonDeserialize(using = DateDeserializer.class)添加到您的字段中。

看一下这个例子:

你的Json-Bean

public class Foo {

    private String            name;

    @JsonProperty
    @JsonDeserialize(using = DateDeserializer.class)
    private Map<String, Object> dates;

    [...] // getter, setter, equals, hashcode
}

<强>解串器

public class DateDeserializer extends JsonDeserializer<Map<String, Object>> {

    private TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {};

    @Override
    public Map<String, Object> deserialize(JsonParser p, DeserializationContext ctxt, Map<String, Object> target) throws IOException, JsonProcessingException {

        Map<String, Long> map = new ObjectMapper().readValue(p, typeRef);

        for(Entry<String, Long> e : map.entrySet()){

            Long value = e.getValue();
            String key = e.getKey();

            if(value instanceof Long){ // or if("date".equals(key)) ...
                target.put(key, new Date(value));
            } else {
                target.put(key, value); // leave as is
            }

        }

        return target;
    }

    @Override
    public Map<String, Object> deserialize(JsonParser paramJsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return this.deserialize(paramJsonParser, ctxt, new HashMap<>());
    }

}

简单测试

public static void main(String[] args) throws Exception {

    Foo foo1 = new Foo();
    foo1.setName("foo");
    foo1.setData(new HashMap<String, Object>(){{
        put("date",   new Date());
        put("bool",   true);
        put("string", "yeah");
    }});
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = mapper.writeValueAsString(foo1);
    System.out.println(jsonStr);
    Foo foo2 = mapper.readValue(jsonStr, Foo.class);

    System.out.println(foo2.equals(foo1));

}

答案 1 :(得分:0)

最后,我提出了这个解决方案。解串器:

library(reshape2) # for melt
library(tidyverse)

# convert all total values to 0 except that for the control ...
data1 <- data1 %>%
mutate(SW_Total = ifelse(Trt != "Control", 0, SW_Total))

#convert to long format
melted <- melt(data1, id=c("Plant","RIL","Trt"))

ggplot(melted, aes(x = RIL, y = value, fill = variable)) + 
  geom_bar(stat = 'identity', position = 'stack') + facet_grid(~ Trt) 

串行:

private TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
};

@Override
public Map<String, Object> deserialize(JsonParser p, DeserializationContext ctxt, Map<String, Object> target) throws IOException {
    Map<String, Object> map = new ObjectMapper().readValue(p, typeRef);

    for (Map.Entry<String, Object> e : map.entrySet()) {
        if (e.getKey().endsWith("[date]")) {
            target.put(e.getKey().substring(0, e.getKey().length() - 6), new Date((Long) e.getValue()));
        }
        else {
            target.put(e.getKey(), e.getValue());
        }
    }

    return target;
}

根据数据类型调整映射键。这很容易扩展。