使用Jackson解析Json文件

8
{
   "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"
            }
         }
      ]
   }
}

我的Pojos是:

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,如果有人能帮助我解析文件并获取对象,我将不胜感激。

我已经尝试了两天,但是没有成功。


1
为了节省大家的时间,我在格式化时验证了JSON,它是有效的。 - Dan Temple
你能改变你的 JSON 吗?还是必须按原样反序列化它? - Michał Ziober
2个回答

18

通常使用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. 为了让jackson解析它们,属性名称必须按照领域对象中提供的方式进行提供。您不能只说这是一个对象,然后开始列表,列表必须有一个属性名称/

在我调整了这些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中存在类名的问题。

  • 我添加了一个OverallWrapper类,该类具有TestSuite属性,以满足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以匹配域名,因为域名在设计上似乎很合理,需要较少的自定义和强制。

然而,我承认你可能没有选择权,因此需要重新设计域名。


0
在这篇博客中,您可以找到一种简单的方法来解析大型JSON文件,而不必直接使用Jackson的ObjectMapper 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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接