【问题标题】:Parse JSON to deeply nested generic with jackson使用杰克逊将 JSON 解析为深度嵌套的泛型
【发布时间】:2017-10-16 10:00:23
【问题描述】:

我一直在尝试各种解决方案来使其正常工作。但没有成功。

我有几个这样的课程

class Level1<T> {

    public Level2<T> l2;
}

class Level2<T> {

    public Level3<T> l3;
}

class Level3<T> {

    public List<T> objectsList;
}

T 在这种情况下可以是任何对象,并且应该可以在运行时解析

我的 JSON 如下所示:

{
    "Level1": {
        "Level2": {
            "Level3": {
                "genericObject": [
                    { 
                      "attribute1": ..., 
                      "attribute2": ...
                    },
                    { 
                      "attribute1": ..., 
                      "attribute2": ...
                    } 
                ]
            }
        }
    }
}

JSON 属性“genericObject”会根据我收到的对象类型更改其名称和属性。

我尝试像这样在我的 ObjectMapper 中定义,其中我将一个 Class 对象传递给我的函数(genericObjectClass):

JavaType javaType = TypeFactory.defaultInstance().constructParametricType(ArrayList.class, List.class, genericObjectClass);
javaType = TypeFactory.defaultInstance().constructParametricType(Level3.class, javaType);
javaType = TypeFactory.defaultInstance().constructParametricType(Level2.class, javaType);
javaType = TypeFactory.defaultInstance().constructParametricType(Level1.class, javaType);

Level1<genericObject> l1 = objectMapper.readValue(jsonString, javaType);

尝试过的解决方案:

(de)serialising Nested Generics in Jackson

How to use Jackson with Generics

Is Jackson really unable to deserialize json into a generic type?

【问题讨论】:

    标签: java json generics jackson nested-generics


    【解决方案1】:

    有几件事情你需要改变

    1. Level1 对象不是根对象,而是一个字段。如果您不想再创建一个包装器对象,请使用UNWRAP_ROOT_VALUE

      mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
      
    2. 整个对象层次结构不需要constructParametricType,只需为链中的顶级类构造它

      constructParametricType(Level1.class, genericObjectClass);
      
    3. 您的 json 字段未映射到 pojo 字段。所以你需要用@JsonProperty("Level2")@JsonProperty("genericObject")等注释你的POJO字段。

    所以你的反序列化代码应该是这样的

    ObjectMapper mapper = new ObjectMapper();
    mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    
    JavaType javaType = TypeFactory.defaultInstance()
             .constructParametricType(Level1.class, c);
    
    mapper.readValue(json, javaType);
    

    类看起来像

    class Level1<T> {
        @JsonProperty("Level2")
        public Level2<T> l2;
    }
    class Level2<T> {
        @JsonProperty("Level3")
        public Level3<T> l3;
    }
    class Level3<T> {
        @JsonProperty("genericObject")
        public List<T> objectsList;
    }
    

    这里是完整的工作gist demo

    【讨论】:

    • 感谢您的回答。但我所说的“genericObject”是指@JsonProperty 会在运行时发生变化。因此我不能做类似@JsonProperty("genericObject") 的事情,因为它可能是多种 POJO。我会按照您建议的方式尝试 TypeFactory,看看它是否有效。谢谢!
    • @alexluz 如果您的 json 中有不同的字段名称,那很好,并且您可能不需要为不同的 POJO 使用 @JsonProperty。但 json 字段名称需要与您要反序列化的 POJO 中的字段名称完全相同。通用与否,它们需要匹配。如果你不能确保,那么你必须编写自定义反序列化器。但是,在您发表评论后,您似乎可以忽略我的这部分答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 1970-01-01
    相关资源
    最近更新 更多