📜  在Java解析 JSON 时如何忽略未知属性?

📅  最后修改于: 2021-10-28 02:21:16             🧑  作者: Mango

在Java中解析 JSON 时存在未知属性,其中使用 Jackson API 在Java解析 JSON 时最常见的问题是当 JSON 包含未知属性时会失败,这意味着Java类没有与所有 JSON 属性对应的所有字段。例如,如果您从 REST Web 服务使用 JSON,并且第二天他们向 JSON 添加了一个新字段,那么代码将中断,因为 Jackson 将抛出UnrecognizedPropertyException并停止解析 JSON。这很麻烦,如果不知道,可能会导致生产问题。如果熟悉杰克逊图书馆,这个问题就可以简单地避免。

方法:

Jackson API 提供了两种忽略未知字段的方法。此处将讨论这两种方法,我们还将了解如何使用它们以及何时使用 @JsonIgnoreProperties 以及何时在 ObjectMapper 级别全局忽略 JSON 中的未知字段。它们如下:

  1. 在类级别使用@JsonIgnoreProperties注释。
  2. ObjectMapper级别使用 configure() 方法。

方法一:使用@JsonIgnoreProperties

如果正在创建 Model 类来表示Java的 JSON,则可以将该类注释为 @JsonIgnoreProperties(ignoreUnknown = true) 以忽略任何未知字段。这意味着,如果稍后在 JSON 上添加一个新字段来表示此模型,那么在Java解析 JSON 时,Jackson 将不会抛出 UnrecognizedPropertyException。这种方法不仅忽略了该模型类的未知属性,而且还提供了更多控制。

例子:

Java
// Java Program that demonstrates the use of
// @JsonIgnoreProperties
  
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.Serializable;
  
/*
 * Java Program to iterate over JSONObject of json-simple
 */
@JsonIgnoreProperties(ignoreUnknown = true)
class Student implements Serializable {
    private static final long serialVersionUID
        = -740085147914603262L;
  
    private String id;
    private String name;
    private String school;
    private String section;
    private String major;
  
    // getters and setters
    public String getID() { return id; }
  
    public void setID(String id) { this.id = id; }
  
    public String getName() { return name; }
  
    public void setName(String id) { this.name = name; }
  
    public String getSchool() { return school; }
  
    public void setSchool(String id) { this.id = id; }
  
    public String getSection() { return id; }
  
    public void setSection(String id) { this.id = id; }
  
    public String getMajor() { return id; }
  
    public void setMajor(String id) { this.id = id; }
  
    @Override public String toString()
    {
  
        return "Student{"
            + "name='" + name + '\'' + ", id='" + id + '\''
            + ", school='" + school + '\'' + ", section='"
            + section + '\'' + ", major='" + major + '\''
            + '}';
    }
}
  
class StudentMain {
    public static void main(String[] args)
        throws IOException
    {
        // JSON string
        String jsonString
            = "{\"name\":\"Krish\",\"id\":\"2019071075\"\"phone\":\"111-111-1111\"}";
        System.out.println("Input json string : ");
        System.out.println(jsonString);
        System.out.println("");
        
        // convert to object;
        Student s = toStudent(jsonString);
        
        // print information
        System.out.println("Generated java class:");
        System.out.println(s);
    }
  
    private static Student toStudent(String jsonData)
        throws IOException
    {
        // create object mapper instance
        ObjectMapper om = new ObjectMapper();
        
        // convert JSON string to Java Object
        return om.readValue(jsonData, Student.class);
    }
}


Java
// Java Program that demonstrates the use of ObjectMapper
// Configuration
  
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
  
/* * Java Program to iterate over JSONObject of json-simple
 */
class JacksonTest {
    // JSON string
    private static String json
        = "{\r\n"
          + "\"name\" : \"Jack Ryan\",\r\n"
          + "\"id\" : \"2019071075\",\r\n"
          + "\"school\" : St. Jude's School,\r\n"
          + "\"section\" : B\r\n"
          + "}";
    public static void main(String args[])
        throws IOException
    {
        // create object mapper instance
        ObjectMapper om = new ObjectMapper();
        // configure ignore unknown properties
        om.configure(DeserializationFeature
                         .FAIL_ON_UNKNOWN_PROPERTIES,
                     false);
        // convert JSON string to Java Object
        Student effectiveJava
            = om.readValue(json, Student.class);
        System.out.println("Input json string");
        System.out.println(json);
        System.out.println("Generated java class: ");
        System.out.println(effectiveJava);
    }
}
  
class Student {
    private String name;
    private String id;
    private String school;
  
    public Student()
    {
        // no argument constructor required by Jackson
    }
  
    public Student(String name, String id, String school)
    {
        this.name = name;
        this.id = id;
        this.school = school;
    }
    // getters and setters
    public String getID() { return id; }
  
    public void setID(String id) { this.id = id; }
  
    public String getName() { return name; }
  
    public void setName(String id) { this.name = name; }
  
    public String getSchool() { return school; }
  
    public void setSchool(String id) { this.id = id; }
  
    @Override public String toString()
    {
        return "Student{"
            + "name='" + name + '\'' + ", id='" + id + '\''
            + ", school='" + school + '\'' + '}';
    }
}


输出:

Input json string :
{"name":"Krish","phone":"111-111-1111"}

Generated java class:
Employee{name='Krish', id='2019071075', school='null', section='null', major='null'}

输出说明:

使用 @JsonIgnoreProperties 注释类的方法允许更好地控制哪些对象应该忽略未知字段,哪些不应该。另一方面,开发人员可能忘记将注解放在类中,然后就会出现问题。

方法 2:使用杰克逊

配置 ObjectMapper 是另一种在解析 JSON 时处理未知属性的方法,这样它在遇到未知属性时就不会失败。这也解决了 UnrecognizedPropertyException 的问题。

此设置通过调用configure() 方法启用,如下所示:

import com.fasterxml.jackson.databind.DeserializationFeature; 
import com.fasterxml.jackson.databind.ObjectMapper; 

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

例子:

Java

// Java Program that demonstrates the use of ObjectMapper
// Configuration
  
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
  
/* * Java Program to iterate over JSONObject of json-simple
 */
class JacksonTest {
    // JSON string
    private static String json
        = "{\r\n"
          + "\"name\" : \"Jack Ryan\",\r\n"
          + "\"id\" : \"2019071075\",\r\n"
          + "\"school\" : St. Jude's School,\r\n"
          + "\"section\" : B\r\n"
          + "}";
    public static void main(String args[])
        throws IOException
    {
        // create object mapper instance
        ObjectMapper om = new ObjectMapper();
        // configure ignore unknown properties
        om.configure(DeserializationFeature
                         .FAIL_ON_UNKNOWN_PROPERTIES,
                     false);
        // convert JSON string to Java Object
        Student effectiveJava
            = om.readValue(json, Student.class);
        System.out.println("Input json string");
        System.out.println(json);
        System.out.println("Generated java class: ");
        System.out.println(effectiveJava);
    }
}
  
class Student {
    private String name;
    private String id;
    private String school;
  
    public Student()
    {
        // no argument constructor required by Jackson
    }
  
    public Student(String name, String id, String school)
    {
        this.name = name;
        this.id = id;
        this.school = school;
    }
    // getters and setters
    public String getID() { return id; }
  
    public void setID(String id) { this.id = id; }
  
    public String getName() { return name; }
  
    public void setName(String id) { this.name = name; }
  
    public String getSchool() { return school; }
  
    public void setSchool(String id) { this.id = id; }
  
    @Override public String toString()
    {
        return "Student{"
            + "name='" + name + '\'' + ", id='" + id + '\''
            + ", school='" + school + '\'' + '}';
    }
}

输出 :

Input json string
 {
   "name" : "Jack Ryan",
   "id" : "2019071075",
   "school" : "St. Jude's School",
   "section" : "B" 
  } 
 Generated java class:
 Student [name=Jack Ryan, id=2019071075, school=St. Jude's School]

输出说明:

根据依赖注入框架配置对象映射器的方法,确保在整个系统中使用相同的对象映射器,将保证整个应用程序中的异常消失,但让开发人员对相关的进化蒙上眼睛发生在正在使用的 API 中。

但是,首选方法是使用 @JsonIgnoreProperties(ignoreUnknown = true) 在类级别忽略未知属性,并且仅在您无法使用此注释对类进行注释时才在 ObjectMapper 级别执行此操作,即您不拥有该类。使用 @JsonIgnoreProperties 注释模型类以避免出现问题也是最佳实践。