【问题标题】:Jackson Default Typing for object containing a field of Map<String, Object>包含 Map<String, Object> 字段的对象的杰克逊默认类型
【发布时间】:2013-07-15 16:00:22
【问题描述】:

所以我一直试图让 Jackson 序列化/反序列化我拥有的一个对象,该对象本质上是结构:

MyObject {
    String a;
    Map<String, Object> map;
}

map 可以保存嵌套映射或“原始”值(StringIntegerLongDouble、...)

显然,由于需要类型信息才能正确反序列化,我不得不告诉 Jackson 这样做——为此我使用了默认类型:

return new ObjectMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, JsonTypeInfo.As.WRAPPER_ARRAY);

对象最终完全按照我的意愿序列化,只在必要的地方添加类型信息:

{
   "a":"SomeString",
   "map":{
      "String1":"String1",
      "Float1":[
         "java.lang.Float",
         1.0
      ],
      "Long1":[
         "java.lang.Long",
         1
      ],
      "Int1":1,
      "Double1":1.0
   }
}

但是,当我尝试使用 Jackson 反序列化此 JSON 时,它失败并出现以下错误:

java.lang.IllegalArgumentException: Can not deserialize instance of <my type> out of START_ARRAY token
at [Source: N/A; line: -1, column: -1] (through reference chain: <my type>["name"])
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:2615)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:2542)
at com.rbsgbm.agile.mongo.dbobject.JacksonDBObjectConverter.fromDBObject(JacksonDBObjectConverter.java:39)
at com.rbsgbm.agile.mongo.DBCursorIterator.next(DBCursorIterator.java:32)
at com.rbsgbm.agile.repository.StorageBasedRepository$StorageBasedQuery$StorageBasedQueryIterator.next(StorageBasedRepository.java:258)
at com.rbsgbm.agile.repository.StorageBasedRepository$StorageBasedQuery$StorageBasedQueryIterator.next(StorageBasedRepository.java:242)
at com.rbs.agile.strategy.strategymanager.store.mongo.MongoStrategyStore.loadStrategies(MongoStrategyStore.java:81)

这表明它对映射中 Jackson 认为不需要类型信息的值感到困惑,因此没有将其包装在数组中。

有人可以建议正确的方法吗?

【问题讨论】:

    标签: java json serialization jackson deserialization


    【解决方案1】:

    您好,请这样做来解决您的问题

    首先使用适当的 getter 和 setter 方法创建一个类 MyObject

    /**
     * @author qualebs
     */
    public class MyObject {
        private String a;
        private Map<String, Object> map;
    
        public String getA() {
            return a;
        }
    
        public void setA(String a) {
            this.a = a;
        }
    
        public Map<String, Object> getMap() {
            return map;
        }
    
        public void setMap(Map<String, Object> map) {
            this.map = map;
        }
    }
    

    然后在要序列化MyObject 的类中使用以下配置创建ObjectMapper 的实例。

    ObjectMapper mapper = new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
            .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    
    // get an create a new MyObject
    MyObject object = new MyObject();
    
    // set the values you want ie the String a and the Map
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("string", "example string");
    map.put("int", 1);
    map.put("long", 1l);
    map.put("double", 2.0);
    // we can also put an array
    map.put("intArray", new int[]{1, 2, 3, 10});
    
    // add the map to your object
    object.setMap(map);
    
    // set the string a
    object.setA("example String 2");
    
    // now we serialize the object
    String mySerializedObj = mapper.writeValueAsString(object);
    
    // to deserialize simply do
    MyObject myUnserializedObj = mapper.readValue(mySerializedObj, MyObject.class);
    

    如果这回答了您的问题,请接受我的回答,我可以使用积分。谢谢。

    【讨论】:

    • 但这不会将类型信息存储下来 - 因此会错误地反序列化地图中的数据。我想将类型信息存储在必要的地方,以便反序列化同类对象。
    • 我添加了一个编辑并启用了默认类型,我已经序列化并确认该对象已使用其类型信息进行序列化,并且反序列化没有错误。再次检查
    • 但我只想将类型信息保存在必要的地方,而不是任何地方。
    • 我也按照你的方式做了,它也可以,IDK可能有什么问题。我正在使用 1.9.2 版本的 jar,我在 apache cassandra zip 中找到了你使用的是什么版本?
    • 我正在使用 Jackson (fasterxml) 2.2.2。
    猜你喜欢
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 2015-03-08
    • 1970-01-01
    • 2018-01-28
    相关资源
    最近更新 更多