Java处理JSON神器:Jackson使用及常用配置详细文档
文章目录
- 一、jackson简介
- 二、jackson注解使用详解
- 1、序列化注解
- 2、反序列化注解
- 3、其他注解
- (1)@JsonIgnoreProperties与@JsonIgnore字段忽略
- (2)@JsonInclude排除null字段
- (3)@JsonIncludeProperties指定序列化的字段
- (4)@JsonIgnoreType忽略类型
- (5)@JsonAutoDetect指定属性是否可见
- (6)@JsonProperty指定字段名
- (7)@JsonFormat指定时间/日期格式
- (8)@JsonUnwrapped指定展开/平铺的值
- (9)@JsonView指示将在其中包含属性以进行序列化/反序列化的视图
- (10)@JsonManagedReference、@JsonBackReference处理循环引用
- (11)@JsonIdentityInfo处理无限递归问题
- (12)@JsonFilter指定过滤器
- 4、处理多态注解
- 5、自定义jackson注解
- 6、禁用jackson注解
- 三、使用ObjectMapper
- 四、处理未知属性的JSON内容
- 五、常见异常与处理方案
- 1、JsonMappingException: Can Not Construct Instance Of
- 2、JsonMappingException: No Suitable Constructor
- 3、JsonMappingException: Root Name Does Not Match Expected
- 4、JsonMappingException: No Serializer Found for Class
- 5、JsonMappingException: Can Not Deserialize Instance Of
- 6、JsonMappingException: Cannot Deserialize Value of Type java.lang.String From Object Value
- 7、UnrecognizedPropertyException
- 8、JsonParseException: Unexpected Character (”’ (code 39))
- 9、JsonParseException: Unexpected Character (‘c’ (code n))
- 10、MismatchedInputException: Cannot Deserialize Instance
一、jackson简介
Java解析json的第三方jar包有很多,fastjson2、Gson、jackson等。
而Spring把jackson作为默认的json解析工具,还是有必要学习一下的。
jackson有着灵活的配置,但是使用起来比较复杂,远没有fastjson2、Gson简单。
github地址:https://github.com/FasterXML/jackson
比较全的官方文档:https://www.baeldung.com/jackson
项目中使用springboot-starter-web
,就自动引入了jackson。
<!-- 该包会引入 jackson-core和jackson-annotations-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
二、jackson注解使用详解
1、序列化注解
(1)@JsonAnyGetter格式化Map
没标注前的结果:{"name":"zhangsan","properties":{"attr2":"val2","attr1":"val1"}}
标注后的结果:{"name":"zhangsan","attr2":"val2","attr1":"val1"}
注意,@JsonAnyGetter
要标注在get
方法上,如果标注在属性上,结果就会是这样:{"name":"zhangsan","properties":{"attr2":"val2","attr1":"val1"},"attr2":"val2","attr1":"val1"}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class Student {
public String name;
private Map<String, String> properties;
public Student(String name) {
this.name = name;
}
public Map<String, String> getProperties() {
return properties;
}
public void add(String attr, String val) {
if (this.properties == null) {
this.properties = new HashMap<>();
}
properties.put(attr, val);
}
public static void main(String[] args) throws JsonProcessingException {
Student bean = new Student("zhangsan");
bean.add("attr1", "val1");
bean.add("attr2", "val2");
String result = new ObjectMapper().writeValueAsString(bean);
System.out.println(result);
}
}
(2)@JsonGetter设置get方法与字段名
@JsonGetter
标注在get方法上,确定一个get方法,并且可以设置格式化的key的名称。
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@JsonGetter("name")
public String getTheName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
Student bean = new Student(1, "zhangsan");
String result = new ObjectMapper().writeValueAsString(bean);
// {"id":1,"name":"zhangsan"}
System.out.println(result);
}
}
(3)@JsonPropertyOrder设置格式化顺序
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
// 指定格式化顺序
@JsonPropertyOrder({ "name", "id" })
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
Student bean = new Student(1, "zhangsan");
String result = new ObjectMapper().writeValueAsString(bean);
// {"name":"zhangsan","id":1}
System.out.println(result);
}
}
(4)@JsonRawValue格式化字符串
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
//@JsonRawValue
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
Student bean = new Student(1, "{\"attr\":\"zhangsan\"}");
String result = new ObjectMapper().writeValueAsString(bean);
// 不用@JsonRawValue:{"id":1,"name":"{\"attr\":\"zhangsan\"}"}
// 用@JsonRawValue:{"id":1,"name":{"attr":"zhangsan"}}
System.out.println(result);
}
}
(5)@JsonValue指定格式化方法
使用@JsonValue
标注的get方法,会作为该对象的格式化方法,该方法的返回值就是格式化后的值。
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@JsonValue
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
Student bean = new Student(1, "zhangsan");
String result = new ObjectMapper().writeValueAsString(bean);
// "zhangsan"
System.out.println(result);
}
}
(6)@JsonRootName对根进行包装
对该对象最外层进行包装
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@JsonRootName(value = "student")
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); // 需要开启根包装
Student bean = new Student(1, "zhangsan");
String result = mapper.writeValueAsString(bean);
// {"student":{"id":1,"name":"zhangsan"}}
System.out.println(result);
}
}
(7)@JsonSerialize指定字段序列化器
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Student {
private int id;
private String name;
// 指定序列化器
@JsonSerialize(using = CustomDateSerializer.class)
private Date birthday;
public Student(int id, String name, Date birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Student bean = new Student(1, "zhangsan", new Date());
String result = mapper.writeValueAsString(bean);
// {"id":1,"name":"zhangsan","birthday":"2024-11-18 04:01:40"}
System.out.println(result);
}
// 需要定义序列化类
public static class CustomDateSerializer extends StdSerializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class<Date> t) {
super(t);
}
@Override
public void serialize(
Date value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
}
2、反序列化注解
(1)@JsonCreator与@JsonProperty指定反序列构造器与字段名
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
private String name;
// 指定构造器和字段名
@JsonCreator
public Student(@JsonProperty("id")int id, @JsonProperty("theName")String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"theName\":\"zhangsan\"}";
Student bean = mapper.readValue(json, Student.class);
System.out.println(bean);
}
}
(2)@JacksonInject注入字段数据
import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
// 指定注入字段
@JacksonInject
private int id;
private String name;
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"zhangsan\"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1); // 将int类型注入为1
Student bean = mapper.reader(inject).forType(Student.class).readValue(json);
System.out.println(bean);
}
}
(3)@JsonAnySetter写入map
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class Student {
private String name;
private Map<String, String> properties;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
// 只能这样写,不能直接放在set方法上
@JsonAnySetter
public void add(String key, String value) {
if (properties == null) {
properties = new HashMap<>();
}
properties.put(key, value);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", properties=" + properties +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"zhangsan\",\"attr2\":\"val2\",\"attr1\":\"val1\"}";
Student bean = mapper.readValue(json, Student.class);
// Student{name='zhangsan', properties={attr2=val2, attr1=val1}}
System.out.println(bean);
}
}
(4)@JsonSetter指定字段名
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
// 指定字段名
@JsonSetter("theName")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"theName\":\"zhangsan\"}";
Student bean = mapper.readValue(json, Student.class);
System.out.println(bean);
}
}
(5)@JsonDeserialize指定字段反序列化器
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Student {
private int id;
private String name;
// 指定反序列化器
@JsonDeserialize(using = CustomDateDeserializer.class)
private Date birthday;
public Student() {
}
public Student(int id, String name, Date birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"name\":\"zhangsan\",\"birthday\":\"2024-11-18 04:01:40\"}";
Student result = mapper.readValue(json, Student.class);
// Student{id=1, name='zhangsan', birthday=Mon Nov 18 04:01:40 GMT+08:00 2024}
System.out.println(result);
}
// 需要定义反序列化类
public static class CustomDateDeserializer extends StdDeserializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class<Date> t) {
super(t);
}
@Override
public Date deserialize(
JsonParser jsonparser, DeserializationContext context)
throws IOException {
String date = jsonparser.getText();
try {
return formatter.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}
(6)@JsonAlias为字段指定多个别名
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Student {
private int id;
// 指定多个别名
@JsonAlias({ "fname", "f_name" })
private String name;
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"fname\":\"zhangsan\"}";
Student result = mapper.readValue(json, Student.class);
System.out.println(result);
}
}
3、其他注解
(1)@JsonIgnoreProperties与@JsonIgnore字段忽略
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
// 类级别,忽略id字段,序列化和反序列化都会忽略
@JsonIgnoreProperties({ "id" })
public class Student {
// 字段级别,忽略id字段,只序列化,反序列化会忽略
@JsonIgnore
private int id;
private String name;
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"name\":\"zhangsan\"}";
Student result = mapper.readValue(json, Student.class);
System.out.println(result);
System.out.println(mapper.writeValueAsString(result));
}
}
(2)@JsonInclude排除null字段
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
// null字段不参与序列化
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Student {
private Integer id;
private String name;
public String getName() {
return name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"zhangsan\"}";
Student result = mapper.readValue(json, Student.class);
System.out.println(result);
System.out.println(mapper.writeValueAsString(result));
}
}
(3)@JsonIncludeProperties指定序列化的字段
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
// 指定序列化的字段
@JsonIncludeProperties({ "name" })
public class Student {
private Integer id;
private String name;
public String getName() {
return name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1, \"name\":\"zhangsan\"}";
Student result = mapper.readValue(json, Student.class);
System.out.println(result);
System.out.println(mapper.writeValueAsString(result));
}
}
(4)@JsonIgnoreType忽略类型
public class User {
public int id;
public Name name;
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
}
}
@Test
public void whenSerializingUsingJsonIgnoreType_thenCorrect()
throws JsonProcessingException, ParseException {
User.Name name = new User.Name("John", "Doe");
User user = new User(1, name);
String result = new ObjectMapper()
.writeValueAsString(user);
assertThat(result, containsString("1"));
assertThat(result, not(containsString("name")));
assertThat(result, not(containsString("John")));
}
(5)@JsonAutoDetect指定属性是否可见
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
private int id;
private String name;
}
@Test
public void whenSerializingUsingJsonAutoDetect_thenCorrect()
throws JsonProcessingException {
PrivateBean bean = new PrivateBean(1, "My bean");
String result = new ObjectMapper()
.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("My bean"));
}
(6)@JsonProperty指定字段名
public class MyBean {
public int id;
private String name;
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
}
@Test
public void whenUsingJsonProperty_thenCorrect()
throws IOException {
MyBean bean = new MyBean(1, "My bean");
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
MyBean resultBean = new ObjectMapper()
.readerFor(MyBean.class)
.readValue(result);
assertEquals("My bean", resultBean.getTheName());
}
(7)@JsonFormat指定时间/日期格式
public class EventWithFormat {
public String name;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "dd-MM-yyyy hh:mm:ss")
public Date eventDate;
}
(8)@JsonUnwrapped指定展开/平铺的值
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public static class Name {
public String firstName;
public String lastName;
}
}
@Test
public void whenSerializingUsingJsonUnwrapped_thenCorrect()
throws JsonProcessingException, ParseException {
UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");
UnwrappedUser user = new UnwrappedUser(1, name);
String result = new ObjectMapper().writeValueAsString(user);
assertThat(result, containsString("John"));
assertThat(result, not(containsString("name")));
}
/*
结果:
{
"id":1,
"firstName":"John",
"lastName":"Doe"
}
*/
(9)@JsonView指示将在其中包含属性以进行序列化/反序列化的视图
// 视图
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
// 使用视图
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
// 测试
@Test
public void whenSerializingUsingJsonView_thenCorrect()
throws JsonProcessingException {
Item item = new Item(2, "book", "John");
String result = new ObjectMapper()
.writerWithView(Views.Public.class)
.writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("2"));
assertThat(result, not(containsString("John")));
}
(10)@JsonManagedReference、@JsonBackReference处理循环引用
public class ItemWithRef {
public int id;
public String itemName;
@JsonManagedReference
public UserWithRef owner;
}
public class UserWithRef {
public int id;
public String name;
@JsonBackReference
public List<ItemWithRef> userItems;
}
@Test
public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
throws JsonProcessingException {
UserWithRef user = new UserWithRef(1, "John");
ItemWithRef item = new ItemWithRef(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, not(containsString("userItems")));
}
(11)@JsonIdentityInfo处理无限递归问题
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class UserWithIdentity {
public int id;
public String name;
public List<ItemWithIdentity> userItems;
}
@Test
public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
throws JsonProcessingException {
UserWithIdentity user = new UserWithIdentity(1, "John");
ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
user.addItem(item);
String result = new ObjectMapper().writeValueAsString(item);
assertThat(result, containsString("book"));
assertThat(result, containsString("John"));
assertThat(result, containsString("userItems"));
}
// 结果
{
"id": 2,
"itemName": "book",
"owner": {
"id": 1,
"name": "John",
"userItems": [
2
]
}
}
(12)@JsonFilter指定过滤器
@JsonFilter("myFilter")
public class BeanWithFilter {
public int id;
public String name;
}
// 我们定义了过滤器,它排除了除名字来自序列化:
@Test
public void whenSerializingUsingJsonFilter_thenCorrect()
throws JsonProcessingException {
BeanWithFilter bean = new BeanWithFilter(1, "My bean");
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
String result = new ObjectMapper()
.writer(filters)
.writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, not(containsString("id")));
}
4、处理多态注解
@JsonTypeInfo–指示序列化中要包含的类型信息的详细信息
@JsonSubTypes–指示注释类型的子类型
@JsonTypeName–定义用于注释类的逻辑类型名
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Zoo {
public Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
}
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
public Dog(String name) {
super(name);
}
}
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likesCream;
public int lives;
public Cat(String name) {
super(name);
}
}
public Zoo(Animal animal) {
this.animal = animal;
}
public static void main(String[] args) throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy");
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper()
.writeValueAsString(zoo);
System.out.println(result);
}
}
5、自定义jackson注解
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id", "dateCreated" })
public @interface CustomAnnotation {}
// 使用
@CustomAnnotation
public class BeanWithCustomAnnotation {
public int id;
public String name;
public Date dateCreated;
}
// 多个注解合一
@Test
public void whenSerializingUsingCustomAnnotation_thenCorrect()
throws JsonProcessingException {
BeanWithCustomAnnotation bean
= new BeanWithCustomAnnotation(1, "My bean", null);
String result = new ObjectMapper().writeValueAsString(bean);
assertThat(result, containsString("My bean"));
assertThat(result, containsString("1"));
assertThat(result, not(containsString("dateCreated")));
}
// 结果
{
"name":"My bean",
"id":1
}
6、禁用jackson注解
@Test
public void whenDisablingAllAnnotations_thenAllDisabled()
throws IOException {
MyBean bean = new MyBean(1, null);
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS); // 禁用注解
String result = mapper.writeValueAsString(bean);
assertThat(result, containsString("1"));
assertThat(result, containsString("name"));
}
三、使用ObjectMapper
public class Car {
private String color;
private String type;
// standard getters setters
}
1、序列化
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
// 序列化到文件 :{"color":"yellow","type":"renault"}
objectMapper.writeValue(new File("target/car.json"), car);
// 序列化到字符串
String carAsString = objectMapper.writeValueAsString(car);
2、反序列化
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
// 从字符串
Car car = objectMapper.readValue(json, Car.class);
// 从文件
Car car = objectMapper.readValue(new File("src/test/resources/json_car.json"), Car.class);
// 从url
Car car = objectMapper.readValue(new URL("file:src/test/resources/json_car.json"), Car.class);
3、强大的JsonNode
可以将JSON解析成JsonNode对象,用于从特定节点检索数据:
String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
// Output: color -> Black
4、反序列化集合
String jsonCarArray =
"[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
// 用类型引用
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
// 反序列化为数组
String jsonCarArray =
"[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);
// print cars
5、反序列化Map
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Map<String, Object> map
= objectMapper.readValue(json, new TypeReference<Map<String,Object>>(){});
6、映射没有的字段,防止报错
ObjectMapper objectMapper = new ObjectMapper();
String jsonString
= "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";
// 映射没有的字段,防止报错
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Car car = objectMapper.readValue(jsonString, Car.class);
JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);
JsonNode jsonNodeYear = jsonNodeRoot.get("year");
String year = jsonNodeYear.asText();
System.out.println(year);
7、自定义序列化/反序列化器
public class CustomCarSerializer extends StdSerializer<Car> {
public CustomCarSerializer() {
this(null);
}
public CustomCarSerializer(Class<Car> t) {
super(t);
}
@Override
public void serialize(
Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("car_brand", car.getType());
jsonGenerator.writeEndObject();
}
}
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));
module.addSerializer(Car.class, new CustomCarSerializer());
mapper.registerModule(module);
Car car = new Car("yellow", "renault");
String carJson = mapper.writeValueAsString(car);
public class CustomCarDeserializer extends StdDeserializer<Car> {
public CustomCarDeserializer() {
this(null);
}
public CustomCarDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) {
Car car = new Car();
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
// try catch block
JsonNode colorNode = node.get("color");
String color = colorNode.asText();
car.setColor(color);
return car;
}
}
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Car.class, new CustomCarDeserializer());
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);
8、处理Date类型
public class Request
{
private Car car;
private Date datePurchased;
// standard getters setters
}
ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
objectMapper.setDateFormat(df); // 指定Date格式化
String carAsString = objectMapper.writeValueAsString(request);
// output: {"car":{"color":"yellow","type":"renault"},"datePurchased":"2016-07-03 11:43 AM CEST"}
9、用建造者模式创建ObjectMapper
ObjectMapper mapper = new ObjectMapperBuilder()
.enableIndentation()
.dateFormat()
.preserveOrder(true)
.build();
四、处理未知属性的JSON内容
1、引出问题
假设有以下实体类:
public class MyDto {
private String stringValue;
private int intValue;
private boolean booleanValue;
// standard constructor, getters and setters
}
解析未知属性,会报错com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
@Test(expected = UnrecognizedPropertyException.class)
public void givenJsonHasUnknownValues_whenDeserializingAJsonToAClass_thenExceptionIsThrown()
throws JsonParseException, JsonMappingException, IOException {
String jsonAsString =
"{\"stringValue\":\"a\"," +
"\"intValue\":1," +
"\"booleanValue\":true," +
"\"stringValue2\":\"something\"}";
ObjectMapper mapper = new ObjectMapper();
MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);
assertNotNull(readValue);
}
// 以下异常:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "stringValue2" (class org.baeldung.jackson.ignore.MyDto),
not marked as ignorable (3 known properties: "stringValue", "booleanValue", "intValue"])
2、解决方案一
// 忽略未知属性
new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
3、解决方案二
// 忽略未知属性
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }
五、常见异常与处理方案
1、JsonMappingException: Can Not Construct Instance Of
public class Zoo {
public Animal animal;
public Zoo() { }
}
abstract class Animal {
public String name;
public Animal() { }
}
class Cat extends Animal {
public int lives;
public Cat() { }
}
@Test(expected = JsonMappingException.class)
public void givenAbstractClass_whenDeserializing_thenException()
throws IOException {
String json = "{"animal":{"name":"lacy"}}";
ObjectMapper mapper = new ObjectMapper();
// JsonMappingException:无法构造实例
mapper.reader().forType(Zoo.class).readValue(json);
}
// 以下是异常信息
com.fasterxml.jackson.databind.JsonMappingException:
Can not construct instance of org.baeldung.jackson.exception.Animal,
problem: abstract types either need to be mapped to concrete types,
have custom deserializer,
or be instantiated with additional type information
at
[Source: {"animal":{"name":"lacy"}}; line: 1, column: 2]
(through reference chain: org.baeldung.jackson.exception.Zoo["animal"])
at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)
解决方案:
// 指定子类类型
@JsonDeserialize(as = Cat.class)
abstract class Animal {...}
2、JsonMappingException: No Suitable Constructor
public class User {
public int id;
public String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
@Test(expected = JsonMappingException.class)
public void givenNoDefaultConstructor_whenDeserializing_thenException()
throws IOException {
String json = "{"id":1,"name":"John"}";
ObjectMapper mapper = new ObjectMapper();
mapper.reader().forType(User.class).readValue(json);
}
// 报错信息
com.fasterxml.jackson.databind.JsonMappingException:
No suitable constructor found for type
[simple type, class org.baeldung.jackson.exception.User]:
can not instantiate from JSON object (need to add/enable type information?)
at [Source: {"id":1,"name":"John"}; line: 1, column: 2]
at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)
解决方案:需要添加一个无参构造器
。
3、JsonMappingException: Root Name Does Not Match Expected
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
@Test
public void
givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect()
throws IOException {
String json = "{"user":{"id":1,"name":"John"}}";
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
UserWithRoot user = mapper.reader()
.forType(UserWithRoot.class)
.readValue(json);
assertEquals("John", user.name);
}
如果有@JsonRootName
,序列化和反序列化时需要注意root。
4、JsonMappingException: No Serializer Found for Class
如果实体类的属性或者get、set方法是私有的,就会报这个错。
解决方案:
@Test
public void givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect()
throws IOException {
UserWithPrivateFields user = new UserWithPrivateFields(1, "John");
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); // 解决方案一:配置能见度
String result = mapper.writer().writeValueAsString(user);
assertThat(result, containsString("John"));
}
// 解决方案二:使用@JsonAutoDetect
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class UserWithPrivateFields { ... }
// 解决方案三:使用public的get、set方法
5、JsonMappingException: Can Not Deserialize Instance Of
注意数组和对象关系
@Test
public void givenJsonOfArray_whenDeserializing_thenCorrect()
throws JsonProcessingException, IOException {
String json
= "[{"id":1,"name":"John"},{"id":2,"name":"Adam"}]";
ObjectMapper mapper = new ObjectMapper();
List<User> users = mapper.reader()
.forType(new TypeReference<List<User>>() {})
.readValue(json);
assertEquals(2, users.size());
}
6、JsonMappingException: Cannot Deserialize Value of Type java.lang.String From Object Value
注意序列化字段的类型。
7、UnrecognizedPropertyException
看第四章,处理未知属性的JSON内容。
8、JsonParseException: Unexpected Character (”’ (code 39))
jackson默认不支持单引号,需要手动开启
@Test
public void
givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect()
throws JsonProcessingException, IOException {
String json = "{'id':1,'name':'John'}";
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); // 支持单引号
ObjectMapper mapper = new ObjectMapper(factory);
User user = mapper.reader().forType(User.class)
.readValue(json);
assertEquals("John", user.name);
}
9、JsonParseException: Unexpected Character (‘c’ (code n))
检查json字符串格式是否正确。
10、MismatchedInputException: Cannot Deserialize Instance
需要使用默认无参构造器
。
原文地址:https://blog.csdn.net/A_art_xiang/article/details/143855746
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!