Java 使用 Jackson 解析 Json 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23290843/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 21:42:08  来源:igfitidea点击:

Parsing Json File using Hymanson

javajsonparsingHymansonpojo

提问by kumarabhishek

{
   "TestSuite":{
      "TestSuiteInfo":{
         "-description":"parse"
      },
      "TestCase":[
         {
            "TestCaseData":{
               "-sequence":"sequential",
               "-testNumber":"2",
               "-testCaseFile":"testcase\Web\Ab.xml"
            }
         },
         {
            "TestCaseData":{
               "-sequence":"sequential",
               "-testNumber":"3",
               "-testCaseFile":"testcase\Web\BC.xml"
            }
         }
      ]
   }
}

My Pojos are:

我的 Pojo 是:

public class TestSuite {    

    private TestSuiteInfo testSuiteInfo;
    private TestCase listOfTestCases;

    public TestSuiteInfo getTestSuiteInfo() {   
        return testSuiteInfo;
    }

    public void setTestSuiteInfo(TestSuiteInfo testSuiteInfo) {
        this.testSuiteInfo = testSuiteInfo;
    }

    public TestCase getListOfTestCases() {
        return listOfTestCases;
    }

    public void setListOfTestCases(TestCase listOfTestCases) {
        this.listOfTestCases = listOfTestCases;
    }
}


public class TestSuiteInfo {

    private String description;

    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}


import java.util.Iterator;
import java.util.List;

public class TestCase {

    private List<TestCaseData> testCaseData;

    public List<TestCaseData> getTestCaseData() {
        return testCaseData;
    }

    public void setTestCaseData(List<TestCaseData> testCaseData) {
        this.testCaseData = testCaseData;
    }
}


public class TestCaseData {

    private String sequence;
    private int testNumber;
    private String testCaseFile;

    public String getSequence() {   
        return sequence;
    }

    public void setSequence(String sequence) {
        this.sequence = sequence;
    }

    public int getTestNumber() {
        return testNumber;
    }

    public void setTestNumber(int testNumber) {
        this.testNumber = testNumber;
    }

    public String getTestCaseFile() {
        return testCaseFile;
    }

    public void setTestCaseFile(String testCaseFile) {
        this.testCaseFile = testCaseFile;
    }
}

I haven't use Hymanson before, will really appreciate if anyone could help me in parsing the file and getting the objects. I am trying to parse this from past two days, but didnt got any success

我以前没有使用过Hyman逊,如果有人能帮助我解析文件并获取对象,我将不胜感激。我试图从过去两天解析这个,但没有取得任何成功

采纳答案by Dan Temple

Usually to parse JSON with the Hymanson library, you would use the ObjectMapperclass like this:

通常要使用 Hymanson 库解析 JSON,您会使用这样的ObjectMapper类:

public static void main(final String[] args) {
    final String json = "some JSON string";
    final ObjectMapper mapper = new ObjectMapper();
    final TestSuite readValue = mapper.readValue(json, TestSuite.class);
    //Then some code that uses the readValue.
    //Keep in mind that the mapper.readValue() method does throw some exceptions
    //So you'll need to handle those too.    
}

However, I wrote a quick test class to check out the parsing of your JSON and came across some issues.

但是,我编写了一个快速测试类来检查您的 JSON 的解析,并遇到了一些问题。

Basically, the design of the JSON and the design of the domain don't match up. So you can either alter the JSON, or you can alter the domain objects.

基本上,JSON 的设计和域的设计不匹配。因此,您可以更改 JSON,也可以更改域对象。

Altering the JSON to fit the domain

更改 JSON 以适应域

  1. The property names that have "-" in them wont parse nicely in Hymanson, so they will need to be removed.
  2. Having the class name before eachof the objects isn't going to help. Hymanson will expect these to be properties, so the Class names will need removing or replacing with property names.
  3. Property names must be provided as they are in the domain objects in order for Hymanson to parse them. You can't just say here's an object and then start a list, the list must have a property name/
  1. 包含“-”的属性名称在 Hymanson 中无法很好地解析,因此需要将其删除。
  2. 在每个对象之前都有类名不会有帮助。Hymanson 期望这些是属性,因此类名需要删除或替换为属性名。
  3. 属性名称必须在域对象中提供,以便 Hymanson 解析它们。你不能只说这里是一个对象然后开始一个列表,列表必须有一个属性名/

After I'd adjusted a these things in the JSON, I got it to parse with the provided domain objects. The JSON I ended up with looked like this:

在我调整了 JSON 中的这些东西之后,我让它用提供的域对象进行解析。我最终得到的 JSON 如下所示:

{
   "testSuiteInfo":{
      "description":"parse"
   },
   "listOfTestCases":{
      "testCaseData":[
         {
            "sequence":"sequential",
            "testNumber":"2",
            "testCaseFile":"testcase\Web\Ab.xml"
         },
         {
            "sequence":"sequential",
            "testNumber":"3",
            "testCaseFile":"testcase\Web\BC.xml"
         }
      ]
   }
}

Here's my test method that does parse the doctored JSON above (please ignore all the escape characters)

这是我的测试方法,它确实解析了上面修改过的 JSON(请忽略所有转义字符)

public static void main(final String[] args) {
    final String json = "{\"testSuiteInfo\":{\"description\":\"parse\"}," +
            "\"listOfTestCases\":{" +
            "\"testCaseData\":[" +
            "{\"sequence\":\"sequential\",\"testNumber\":\"2\",\"testCaseFile\":\"testcase\\Web\\Ab.xml\"}," +
            "{\"sequence\":\"sequential\",\"testNumber\":\"3\",\"testCaseFile\":\"testcase\\Web\\BC.xml\"}" +
            "]" +
            "}" +
            "}";

    final ObjectMapper mapper = new ObjectMapper();

    try {
        final TestSuite readValue = mapper.readValue(json, TestSuite.class);
        System.out.println(readValue.getListOfTestCases()); //just a test to see if the object is built
    }
    catch (final Exception e) {
        e.printStackTrace();
    }
}

Altering the domain to fit the JSON

更改域以适合 JSON

Firstly, the main issues is having the Class names as the property identifiers. That makes it quite difficult to work with this JSON in the usual manner. I've had to add a couple of wrapper classes to get around the class names being in the JSON.

首先,主要问题是将类名称作为属性标识符。这使得以通常的方式使用这个 JSON 变得非常困难。我不得不添加几个包装类来绕过 JSON 中的类名。

  • I've added an OverallWrapperclass that has a TestSuiteproperty to cater for the TestSuite class name in the JSON.

  • I've also added a TestCaseDataWrapperclass to cater for the TestCaseData class names in the list in the JSON.

  • I removed the TestCase class all together as that just became a property on one of the other classes.

  • Then to make the property names match up with the objects, I've used the @JsonPropertyannotation.

  • 我添加了一个OverallWrapper类,该类具有TestSuite满足 JSON 中 TestSuite 类名称的属性。

  • 我还添加了一个TestCaseDataWrapper类来满足 JSON 列表中的 TestCaseData 类名称。

  • 我一起删除了 TestCase 类,因为它只是成为其他类之一的属性。

  • 然后为了使属性名称与对象匹配,我使用了@JsonProperty注释。

Here are the classes after the modifications, and the ultimate parser test method that works and parses the JSON. (again, excuse all the escape characters in the JSON string)

下面是修改后的类,以及最终解析 JSON 的解析器测试方法。(再次原谅 JSON 字符串中的所有转义字符)

import org.codehaus.Hymanson.annotate.JsonProperty;         

public class OverallWrapper {                              

    private TestSuite testSuite;                           

    @JsonProperty("TestSuite")                             
    public TestSuite getTestSuite() {                      
        return this.testSuite;                             
    }                                                      

    public void setTestSuite(final TestSuite testSuite) {  
        this.testSuite = testSuite;                        
    }                                                      
}



import java.util.List;                                                                                                                                  
import org.codehaus.Hymanson.annotate.JsonProperty;                              

public class TestSuite {                                                        

    private TestSuiteInfo testSuiteInfo;                                        

    private List<TestCaseDataWrapper> testCaseData;                             

    @JsonProperty("TestCase")                                                   
    public List<TestCaseDataWrapper> getTestCaseData() {                        
        return this.testCaseData;                                               
    }                                                                           

    public void setTestCaseData(final List<TestCaseDataWrapper> testCaseData) { 
        this.testCaseData = testCaseData;                                       
    }                                                                           

    @JsonProperty("TestSuiteInfo")                                              
    public TestSuiteInfo getTestSuiteInfo() {                                   
        return this.testSuiteInfo;                                              
    }                                                                           

    public void setTestSuiteInfo(final TestSuiteInfo testSuiteInfo) {           
        this.testSuiteInfo = testSuiteInfo;                                     
    }                                                                                                                                                   
}          



import org.codehaus.Hymanson.annotate.JsonProperty;          

public class TestSuiteInfo {                                

    private String description;                             

    @JsonProperty("-description")                           
    public String getDescription() {                        
        return this.description;                            
    }                                                       
    public void setDescription(final String description) {  
        this.description = description;                     
    }                                                       
}                                                                                                                                



import org.codehaus.Hymanson.annotate.JsonProperty;                  

public class TestCaseDataWrapper {                                  

    @JsonProperty("TestCaseData")                                   
    private TestCaseData testcaseData;                              

    public TestCaseData getTestcaseData() {                         
        return this.testcaseData;                                   
    }                                                               

    public void setTestcaseData(final TestCaseData testcaseData) {  
        this.testcaseData = testcaseData;                           
    }                                                               
}       



import org.codehaus.Hymanson.annotate.JsonProperty;             

public class TestCaseData {                                    

    private String sequence;                                   
    private int testNumber;                                    
    private String testCaseFile;                               

    @JsonProperty("-sequence")                                 
    public String getSequence() {                              
        return this.sequence;                                  
    }                                                          

    public void setSequence(final String sequence) {           
        this.sequence = sequence;                              
    }                                                          

    @JsonProperty("-testNumber")                               
    public int getTestNumber() {                               
        return this.testNumber;                                
    }                                                          

    public void setTestNumber(final int testNumber) {          
        this.testNumber = testNumber;                          
    }                                                          

    @JsonProperty("-testCaseFile")                             
    public String getTestCaseFile() {                          
        return this.testCaseFile;                              
    }                                                          

    public void setTestCaseFile(final String testCaseFile) {   
        this.testCaseFile = testCaseFile;                      
    }                                                          
}                                                              



public static void main(final String[] args) {

    final String json = "{\"TestSuite\":{\"TestSuiteInfo\":{\"-description\":\"parse\"},\"TestCase\":[" +
            "{\"TestCaseData\":{\"-sequence\":\"sequential\",\"-testNumber\":\"2\",\"-testCaseFile\":\"testcase\\Web\\Ab.xml\"}}," +
            "{\"TestCaseData\":{\"-sequence\":\"sequential\",\"-testNumber\":\"3\",\"-testCaseFile\":\"testcase\\Web\\BC.xml\"}}" +
            "]}}";

    final ObjectMapper mapper = new ObjectMapper();

    try {
        final OverallWrapper readValue = mapper.readValue(json, OverallWrapper.class);

        System.out.println(readValue.getTestSuite());
    }
    catch (final Exception e) {
        e.printStackTrace();
    }
}

Summing up

加起来

The ultimate issue is that the domain doesn't marry up with the JSON.

最终的问题是域与 JSON 不匹配。

Personally I prefer to change the JSON to marry up to the domain, as the domain seems to make sense in it's design and requires less customization and forcing.

就我个人而言,我更喜欢更改 JSON 以与域结合,因为域的设计似乎很有意义,并且需要较少的定制和强制。

However, I do accept that you may not have that choice, hence the redesign of the domain.

但是,我确实接受您可能没有那个选择,因此重新设计了域。

回答by Juan Rojas

In this blog you can find a simple way to parse a large json file without directly using Hymanson's ObjectMapper https://www.ngdata.com/parsing-a-large-json-file-efficiently-and-easily/

在此博客中,您可以找到一种无需直接使用 Hymanson 的 ObjectMapper 即可解析大型 json 文件的简单方法 https://www.ngdata.com/parsing-a-large-json-file-efficiently-and-easily/

With jp.skipChildren() and nested loops you can reach to your section of interest and once you are there simply break the nested loops using a label:

使用 jp.skipChildren() 和嵌套循环,您可以到达您感兴趣的部分,一旦到达,只需使用标签打破嵌套循环:

outerloop: while (jp.nextToken() != JsonToken.END_OBJECT) {
  //...nested loops here
  break outerloop;
  //...closing loops
}

I copied the code for reference:

我复制了代码以供参考:

import org.codehaus.Hymanson.map.*;
import org.codehaus.Hymanson.*;

import java.io.File;

public class ParseJsonSample {
  public static void main(String[] args) throws Exception {
    JsonFactory f = new MappingJsonFactory();
    JsonParser jp = f.createJsonParser(new File(args[0]));

    JsonToken current;

    current = jp.nextToken();
    if (current != JsonToken.START_OBJECT) {
      System.out.println("Error: root should be object: quiting.");
      return;
    }

    while (jp.nextToken() != JsonToken.END_OBJECT) {
      String fieldName = jp.getCurrentName();
      // move from field name to field value
      current = jp.nextToken();
      if (fieldName.equals("records")) {
        if (current == JsonToken.START_ARRAY) {
          // For each of the records in the array
          while (jp.nextToken() != JsonToken.END_ARRAY) {
            // read the record into a tree model,
            // this moves the parsing position to the end of it
            JsonNode node = jp.readValueAsTree();
            // And now we have random access to everything in the object
            System.out.println("field1: " + node.get("field1").getValueAsText());
            System.out.println("field2: " + node.get("field2").getValueAsText());
          }
        } else {
          System.out.println("Error: records should be an array: skipping.");
          jp.skipChildren();
        }
      } else {
        System.out.println("Unprocessed property: " + fieldName);
        jp.skipChildren();
      }
    }                
  }
}

From the blog:

来自博客:

The nextToken() call each time gives the next parsing event: start object, start field, start array, start object, …, end object, …, end array, …

nextToken() 每次调用都会给出下一个解析事件:起始对象、起始字段、起始数组、起始对象、……、结束对象、……、结束数组、……

The jp.skipChildren() is convenient: it allows to skip over a complete object tree or an array without having to run yourself over all the events contained in it.

jp.skipChildren() 很方便:它允许跳过完整的对象树或数组,而不必自己遍历其中包含的所有事件。

All the credits go to the blog's author: Molly Galetto

所有学分归博客作者所有:Molly Galetto