【问题标题】:Parsing Json File using Jackson使用 Jackson 解析 Json 文件
【发布时间】:2014-06-11 00:48:27
【问题描述】:
{
   "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"
            }
         }
      ]
   }
}

我的 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;
    }
}

我以前没有使用过 Jackson,如果有人可以帮助我解析文件和获取对象,我将不胜感激。 我试图从过去两天解析这个,但没有成功

【问题讨论】:

  • 为了节省时间,我在格式化时验证了 JSON,它是有效的。
  • 您可以更改您的JSON 还是必须按原样反序列化它?

标签: java json parsing jackson pojo


【解决方案1】:

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

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

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

我复制了代码供参考:

import org.codehaus.jackson.map.*;
import org.codehaus.jackson.*;

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();
      }
    }                
  }
}

来自博客:

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

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

所有功劳归博客作者所有:Molly Galetto

【讨论】:

    【解决方案2】:

    通常要使用 Jackson 库解析 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.    
    }
    

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

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

    更改 JSON 以适应域

    1. 其中包含“-”的属性名称在 jackson 中无法很好地解析,因此需要将其删除。
    2. 在每个对象之前都有类名并没有帮助。 Jackson 会期望这些是属性,因此类名称将需要删除或替换为属性名称。
    3. 必须提供在域对象中的属性名称,以便杰克逊解析它们。你不能只说这里是一个对象然后开始一个列表,列表必须有一个属性名/

    在我在 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"
             }
          ]
       }
    }
    

    这是我的测试方法,它可以解析上面修改过的 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();
        }
    }
    

    更改域以适应 JSON

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

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

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

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

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

    这里是修改后的类,以及可以工作和解析 JSON 的最终解析器测试方法。 (再次,请原谅 JSON 字符串中的所有转义字符)

    import org.codehaus.jackson.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.jackson.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.jackson.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.jackson.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.jackson.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();
        }
    }
    

    总结

    最终的问题是域没有与 JSON 结合。

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

    但是,我承认您可能没有这个选择,因此重新设计了域。

    【讨论】:

      猜你喜欢
      • 2018-06-30
      • 1970-01-01
      • 2017-09-06
      • 2015-07-29
      • 1970-01-01
      • 2017-09-05
      • 1970-01-01
      • 2012-07-05
      • 1970-01-01
      相关资源
      最近更新 更多