【问题标题】:Deserialising complex nested Json using Jackson使用 Jackson 反序列化复杂的嵌套 Json
【发布时间】:2021-03-20 17:29:58
【问题描述】:

我正在努力将复杂的嵌套 Json 数据反序列化为 Java 对象,我认为我的类结构是错误的。这是我的 Json 数据:

    {
"resultsPerPage": 20,
"startIndex": 0,
"totalResults": 2,
"result": {
    "dataType": "CPE",
    "feedVersion": "1.0",
    "cpeCount": 2,
    "feedTimestamp": "2021-03-19T13:06",
    "cpes": [
        {
            "deprecated": false,
            "cpe23Uri": "cpe:2.3:o:microsoft:windows_10:1511:*:*:*:*:*:x64:*",
            "lastModifiedDate": "2015-12-09T17:28Z",
            "titles": [
                {
                    "title": "Microsoft Windows 10 1511 64-bit",
                    "lang": "en_US"
                }
            ],
            "refs": [
                {
                    "ref": "https://www.microsoft.com/en-us/",
                    "type": "Vendor"
                }
            ],
            "deprecatedBy": [],
            "vulnerabilities": [
                "CVE-2016-0174",
                "CVE-2016-0171"
            ]
        }

这是我将 Json 数据映射到的类:

public class RESPONSE {

    Result result;
}

class Result {

    List<Cpes> cpes;
}

class Cpes {

    String cpe23Uri;
    List<Titles> titles;
    List<String> vulnerabilities;
}

class Titles{

    String title;
}

当我在下面的代码中调试我的代码r 时为空,我认为这是因为我的 RESPONSE 类设置不正确。

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        RESPONSE r = mapper.readValue(response.getContent(), RESPONSE.class);

        System.out.println(r);

【问题讨论】:

  • 请遵守 Java 命名约定,否则会使您的代码难以阅读。类应该是PascalCase
  • 我会编辑,这背后的原因是因为 RESPONSE 是 HTTP 响应,我很容易记住这一点。 cpes 是一个疏忽,我现在将更正。
  • 并且没有抛出异常?
  • 无异常,只是结果返回null。但是我知道 HTTP 请求正在工作,因为我已经通过打印它进行了检查。一切都在那里。
  • 你能尝试在你的类中添加getter和setter吗?可能是因为他们,Jackson 无法映射。

标签: java json jackson


【解决方案1】:

您的对象模型应该与您尝试读取的 JSON 的结构相匹配。例如,它必须如下所示:

public class Response {
    private int resultsPerPage;
    private int startIndex;
    private int totalResults;
    private Result result;
    
    // Should include getters and setters
}

public class Result {
    private String dataType;
    private String feedVersion;
    private int cpeCount;
    private String feedTimestamp;
    private CPE[] cpes;

    // Should include getters and setters
}

public class CPE {
    private boolean deprecated;
    private String cpe23Uri;
    private String lastModifiedDate;
    private Title[] titles;
    private Ref[] refs;
    private String[] deprecatedBy;
    private String[] vulnerabilities;

    // Should include getters and setters
}

public class Title {
    private String title;
    private String lang;

    // Should include getters and setters
}

public class Ref {
    private String ref;
    private String type;

    // Should include getters and setters
}

请注意,为了保持代码示例简短,我省略了 getter 和 setter。

编辑:正如 Tugrul 在下面指出的那样,由于禁用了未知属性上的失败,因此如果模型中缺少字段,它不会失败。唯一的问题是缺少 getter 和 setter。

【讨论】:

  • 我不认为Java 类应该包含Jackson 映射的所有JSON 字段。假设您从 CPE 课程中删除了 2 个字段,Jackson 映射了匹配的其他字段。在这些问题中,没有 getter 和 setter 方法,可能这就是看到 null 的原因。
  • 啊,是的,你是对的。他已禁用未知属性行为的失败。添加 getter 和 setter 应该可以正常工作。
  • 使用列表也应该可以,尽管我在示例中使用了数组。
  • 你是对的,添加 getter 和 setter 确实使它适用于 List 和数组。你能解释一下这个原因吗?因为没有调用来获取或设置任何属性。我觉得很奇怪!
【解决方案2】:

我还找到了解决此问题的另一种方法以供将来参考。

我使用树数据结构来访问我的 Json 字段,这意味着我可以声明一个平面类:

public class Test {

    private String cpe23Uri;
    private String title;
    private List<String> vulnerabilities;


    public String getCpe23Uri() {
        return cpe23Uri;
    }

    public void setCpe23Uri(String cpe23Uri) {
        this.cpe23Uri = cpe23Uri;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<String> getVulnerabilities() {
        return vulnerabilities;
    }

    public void setVulnerabilities(List<String> vulnerabilities) {
        this.vulnerabilities = vulnerabilities;
    }
}

然后我使用Tree进行映射

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        JsonNode resultNode = mapper.readTree(response.getContent());

        Test t = new Test();

        t.setCpe23Uri(resultNode.get("result").get("cpes").get(0).get("cpe23Uri").textValue());

【讨论】:

    猜你喜欢
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    • 2012-07-29
    • 1970-01-01
    相关资源
    最近更新 更多