在Java中解析 JSON 时存在未知属性,其中使用 Jackson API 在Java解析 JSON 时最常见的问题是当 JSON 包含未知属性时会失败,这意味着Java类没有与所有 JSON 属性对应的所有字段。例如,如果您从 REST Web 服务使用 JSON,并且第二天他们向 JSON 添加了一个新字段,那么代码将中断,因为 Jackson 将抛出UnrecognizedPropertyException并停止解析 JSON。这很麻烦,如果不知道,可能会导致生产问题。如果熟悉杰克逊图书馆,这个问题就可以简单地避免。
方法:
Jackson API 提供了两种忽略未知字段的方法。此处将讨论这两种方法,我们还将了解如何使用它们以及何时使用 @JsonIgnoreProperties 以及何时在 ObjectMapper 级别全局忽略 JSON 中的未知字段。它们如下:
- 在类级别使用@JsonIgnoreProperties注释。
- 在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);
Note: Unknown properties will be ignored by this for any JSON it’s going to parse. This option should only be used if you can’t annotate a class with @JsonIgnoreProperties annotation.
例子:
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 注释模型类以避免出现问题也是最佳实践。