文章目录
- 一、Jackson介绍
- 二、基础序列化和反序列化
- 1、快速入门
- 2、序列化API
- 3、反序列化API
- 4、常用配置
- 三、常用注解
- 1、@JsonProperty
- 2、@JsonAlias
- 3、@JsonIgnore
- 4、@JsonIgnoreProperties
- 5、@JsonFormat
- 6、@JsonPropertyOrder
- 四、高级特性
- 1、处理泛型
- 1.1、反序列化List泛型
- 1.2、反序列化Map泛型
- 2、自定义序列化和反序列化
一、Jackson介绍
- Jackson库的核心功能是将
Java对象转换为json字符串(序列化)
以及将json字符串转换为Java对象(反序列化)
- SpringMVC默认json解析器便是Jackson
与其他Java的json的框架相比
- Jackson 解析
大
的json文件速度比较快 - Jackson 运行时占用内存比较
低
,性能比较好 - Jackson 有
灵活
的API,可以很容易进行扩展和定制
核心模块由三部分组成
jackson-core,核心包
,提供基于"流模式"解析的相关API(JsonPaser和JsonGenerator),生成和解析jsonjackson-annotations,注解包
,提供标准注解功能jackson-databind ,数据绑定包
,提供基于"对象绑定"解析的相关API(ObjectMapper)和"树模型"解析的相关API(JsonNode)
其中 jackson-databind内部依赖了jackson-annotations与ackson-core,故只导入jackson-databind即可
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.0</version>
</dependency>
二、基础序列化和反序列化
ObjectMapper
是Jackson序列化和反序列化的核心类,提供了许多用于定制序列化和反序列化的方法和配置选项- 默认情况下,ObjectMapper在序列化对象时,将实体所有的字段一一序列化,无论这些字段是否有值,是否为
null
- 注意:如果实体的某个字段没有提供
getter
方法,则该字段不会被序列化 - ObjectMapper主要用于对Java对象(比如 POJO、List、Set、Map等等)进行序列化与反序列化
1、快速入门
@Testpublic void test1() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();User user = new User();user.setAge(20);user.setBirthday(new Date());user.setName("张三");user.setAddress(null);// 序列化String jsonString = objectMapper.writeValueAsString(user);System.out.println("序列化字符串:" + jsonString);// 反序列化User userFromJson = objectMapper.readValue(jsonString, User.class);System.out.println("反序列化结果:" + userFromJson);}
输出结果:
序列化字符串:{"age":20,"name":"张三","birthday":1721266913536,"address":null}
反序列化结果:User(age=20, name=张三, birthday=Thu Jul 18 09:41:53 CST 2024, address=null)
2、序列化API
- String writeValueAsString(Object value)
(最常用)
- 将任何Java对象()如 POJO、List、Set、Map等)序列化为
json字符串
- 如果对象中某个属性的值为null,则默认也会序列化为null
- 如果value为null,返回序列化的结果也返回null
- 将任何Java对象()如 POJO、List、Set、Map等)序列化为
- byte[] writeValueAsBytes(Object value)
- 将Java对象序列化为
字节数组
- 将Java对象序列化为
- writeValue(File resultFile, Object value)
- 将Java对象序列化并输出指定
文件
中
- 将Java对象序列化并输出指定
- writeValue(OutputStream out, Object value)
- 将Java对象序列化并输出到指定字节
输出流
中
- 将Java对象序列化并输出到指定字节
@Test
public void test2() throws IOException {ObjectMapper objectMapper = new ObjectMapper();User user = new User();user.setAge(20);user.setBirthday(new Date());user.setName("张三");user.setAddress(null);// 序列化bytbyte[] bytes = objectMapper.writeValueAsBytes(user);System.out.println("序列化字节数组:" + new String(bytes));// 序列化到文件objectMapper.writeValue(new File("/Users/xuchang/Documents/json.txt"), user);
}
输出结果:
3、反序列化API
- T readValue(String content, Class valueType)
(最常用)
- 从给定的
json字符串
反序列化为Java对象 - valueType表示反序列化的任何
Class对象
(如 POJO、List、Set、Map等) - content为空或者为null,都会报错
- 从给定的
- T readValue(byte[] src, Class valueType)
- 将json内容的
字节数组
反序列化为Java对象
- 将json内容的
- T readValue(File src, Class valueType)
- 将本地json内容的
文件
反序列化为Java对象
- 将本地json内容的
- T readValue(InputStream src, Class valueType)
- 将json内容的
字节输入流
反序列化为Java对象
- 将json内容的
- T readValue(Reader src, Class valueType)
- 将json内容的
字符输入流
反序列化为Java对象
- 将json内容的
- T readValue(URL src, Class valueType)
- 通过
网络url
地址将json内容反序列化为Java对象
- 通过
4、常用配置
private static final ObjectMapper objectMapper;static {// 创建ObjectMapper对象objectMapper = new ObjectMapper();// configure方法 配置一些需要的参数// 转换为格式化的json 显示出来的格式美化objectMapper.enable(SerializationFeature.INDENT_OUTPUT);// 序列化的时候序列对象的那些属性// JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化// JsonInclude.Include.ALWAYS 所有属性// JsonInclude.Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化// JsonInclude.Include.NON_NULL 属性为NULL 不序列化objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);// 反序列化时,遇到未知属性会不会报错// true - 遇到没有的属性就报错// false - 没有的属性不会管,不会报错objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 如果是空对象的时候,不抛异常objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 忽略 transient 修饰的属性objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);// 去除默认时间戳格式objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);// 设置为中国北京时区objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));// 序列化日期格式 Date类型格式化objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 处理java8不同时间类型JavaTimeModule module = new JavaTimeModule();module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(("HH:mm:ss"))));module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));// 序列换成json时,将所有的long变成string(因为js中得数字类型不能包含所有的java long值)module.addSerializer(Long.TYPE, ToStringSerializer.instance);module.addSerializer(Long.class, ToStringSerializer.instance);objectMapper.registerModule(module);
}@Test
public void testObjectMapper() throws JsonProcessingException {User user = new User();user.setId(1770376103094779915L);user.setAge(20);user.setBirthday(new Date());user.setName("张三");user.setAddress(null);user.setLocalDateTime(LocalDateTime.now());// 序列化String jsonString = objectMapper.writeValueAsString(user);System.out.println("序列化字符串:" + jsonString);// 注意这里添加不存在的属性hobby,反序列化不会报错jsonString = "{\"id\":1770376103094779915,\"age\":20,\"name\":\"张三\",\"birthday\":\"2024-07-19 11:02:19\",\"hobby\":\"打篮球\"}";// 反序列化User userFromJson = objectMapper.readValue(jsonString, User.class);System.out.println("反序列化结果:" + userFromJson);
}
@Data
public class User {private Long id;private Integer age;private String name;private Date birthday;private String address;private LocalDateTime localDateTime;
}
输出结果:
序列化字符串:{"id" : "1770376103094779915","age" : 20,"name" : "张三","birthday" : "2024-07-19 14:27:48","localDateTime" : "2024-07-19 14:27:48"
}
反序列化结果:User(id=1770376103094779915, age=20, name=张三, birthday=Fri Jul 19 11:02:19 CST 2024, address=null, localDateTime=null)
三、常用注解
1、@JsonProperty
- 用于在Java对象的属性和json字段之间建立映射关系
value
:用于指定json属性的名称,当Java属性和json属性名称不一致时使用index
:指示此属性的数字索引的属性access
:用于指定该属性的访问方式- JsonAccess.READ_ONLY(只读-序列化可见)
- JsonAccess.WRITE_ONLY(只写-反序列化可见)
- JsonAccess.READ_WRITE(可读可写)
@Test
public void test3() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();User user = new User();user.setAge(18);user.setName("张三");user.setAddress("北京");user.setBirthday(new Date());// 序列化为json字符串String jsonString = objectMapper.writeValueAsString(user);System.out.println(jsonString);// 反序列化为对象String userJson = "{\"age\":18,\"user_address\":\"北京\",\"user_birthday\":1721309276459,\"user_name\":\"张三\"}";User userValue = objectMapper.readValue(userJson, User.class);System.out.println(userValue);
}@Data
public class User {@JsonProperty(index = 0)private Integer age;@JsonProperty(value = "user_name", access = JsonProperty.Access.READ_ONLY, index = 3)private String name;@JsonProperty(value = "user_birthday", access = JsonProperty.Access.WRITE_ONLY, index = 2)private Date birthday;@JsonProperty(value = "user_address", access = JsonProperty.Access.READ_WRITE, index = 1)private String address;
}
输出结果:
{"age":18,"user_address":"北京","user_name":"张三"}
User(age=18, name=null, birthday=Thu Jul 18 21:27:56 CST 2024, address=北京)
- 序列化属性名称及value设置的名称
- 序列化根据index属性排序,反序列化还是类自上而下的顺序
- 只读属性可以序列化,只写属性可以反序列化(读和写是相对内存中对象来理解的)
2、@JsonAlias
- 在反序列化的时候可以让Bean的属性
接收多个
json字段的名称
@Test
public void test4() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();// 反序列化为对象String userJson = "{\"age\":18,\"address\":\"北京\",\"birthday\":1721309276459,\"nick_name\":\"张三\"}";User userValue = objectMapper.readValue(userJson, User.class);System.out.println(userValue);
}@Data
public class User {private Integer age;@JsonAlias(value = {"nick_name","vip_name"})private String name;private Date birthday;private String address;
}
输出结果:
User(age=18, name=张三, birthday=Thu Jul 18 21:27:56 CST 2024, address=北京)
3、@JsonIgnore
- 序列化时将java bean中的一些属性
忽略掉
,序列化和反序列化都受影响 - 一般标记在属性或者方法上,返回的json数据即不包含该属性
@Test
public void test5() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();User user = new User();user.setAge(18);user.setName("张三");user.setAddress("北京");user.setBirthday(new Date());// 序列化为json字符串String jsonString = objectMapper.writeValueAsString(user);System.out.println(jsonString);// 反序列化为对象String userJson = "{\"age\":18,\"address\":\"北京\",\"birthday\":1721309276459,\"name\":\"张三\"}";User userValue = objectMapper.readValue(userJson, User.class);System.out.println(userValue);
}
@Data
public class User {@JsonIgnoreprivate Integer age;@JsonIgnoreprivate String name;private Date birthday;private String address;
}
输出结果:
{"birthday":1721310730459,"address":"北京"}
User(age=null, name=null, birthday=Thu Jul 18 21:27:56 CST 2024, address=北京)
4、@JsonIgnoreProperties
- 序列化时将java bean中的
一些属性忽略掉
,序列化和反序列化都受影响
@Data
@JsonIgnoreProperties({"age", "name"})
public class User {private Integer age;private String name;private Date birthday;private String address;
}
5、@JsonFormat
- 时间格式化注解
pattern
: 表示日期的格式,比如:yyyy-MM-dd HH:mm:sstimezone
: 默认是GMT,中国需要GMT+8
- 中国时间(Asia/Shanghai) = 格林尼治时间(GMT)+ 8
- 格林尼治时间(GMT) = 世界协调时间(UTC) + 0
@Test
public void test6() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();User user = new User();user.setAge(18);user.setName("张三");user.setAddress("北京");user.setBirthday(new Date());// 序列化为json字符串String jsonString = objectMapper.writeValueAsString(user);System.out.println(jsonString);// 反序列化为对象User userValue = objectMapper.readValue(jsonString, User.class);System.out.println(userValue);
}
@Data
public class User {private Integer age;private String name;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date birthday;private String address;
}
输出结果:
{"age":18,"name":"张三","birthday":"2024-07-18 22:10:36","address":"北京"}
User(age=18, name=张三, birthday=Thu Jul 18 22:10:36 CST 2024, address=北京)
6、@JsonPropertyOrder
- 用于指定实体生成json时的
属性顺序
// 自定义顺序
@JsonPropertyOrder({"name", "age", "address"})
//按字母排序
@JsonPropertyOrder(alphabetic=true)
四、高级特性
1、处理泛型
1.1、反序列化List泛型
- 可以使用
CollectionType
类型反序列化,也可以构造TypeReference
反序列化
@Test
public void test7() throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();CollectionType javaType = mapper.getTypeFactory().constructCollectionType(List.class, User.class);// 造数据List<User> list = new ArrayList<>();for (int i = 0; i < 3; i++) {User user = new User();user.setId((long) i);user.setName("张三" + i);list.add(user);}System.out.println("序列化");String jsonInString = mapper.writeValueAsString(list);System.out.println(jsonInString);System.out.println("反序列化:使用 javaType");List<User> userList1 = mapper.readValue(jsonInString, javaType);System.out.println(userList1);System.out.println("反序列化:使用 TypeReference");List<User> userList2 = mapper.readValue(jsonInString, new TypeReference<List<User>>() {});System.out.println(userList2);
}
@Data
public class User {private Long id;private String name;
}
输出:
序列化
[{"id":0,"name":"张三0"},{"id":1,"name":"张三1"},{"id":2,"name":"张三2"}]
反序列化:使用 javaType
[User(id=0, name=张三0), User(id=1, name=张三1), User(id=2, name=张三2)]
反序列化:使用 TypeReference
[User(id=0, name=张三0), User(id=1, name=张三1), User(id=2, name=张三2)]
1.2、反序列化Map泛型
- 可以使用
MapType
类型反序列化,也可以构造TypeReference
反序列化
@Test
public void test8() throws IOException {ObjectMapper mapper = new ObjectMapper();//第二参数是 map 的 key 的类型,第三参数是 map 的 value 的类型MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, User.class);// 造数据Map<String, User> map = new HashMap<>();for (int i = 0; i < 3; i++) {User user = new User();user.setId((long) i);user.setName("张三" + i);map.put("key" + i, user);}System.out.println("序列化");String jsonInString = mapper.writeValueAsString(map);System.out.println(jsonInString);System.out.println("反序列化: 使用 javaType");Map<String, User> userMap1 = mapper.readValue(jsonInString, javaType);System.out.println(userMap1);System.out.println("反序列化: 使用 TypeReference");Map<String, User> userMap2 = mapper.readValue(jsonInString, new TypeReference<Map<String, User>>() {});System.out.println(userMap2);
}
输出结果:
序列化
{"key1":{"id":1,"name":"张三1"},"key2":{"id":2,"name":"张三2"},"key0":{"id":0,"name":"张三0"}}
反序列化: 使用 javaType
{key1=User(id=1, name=张三1), key2=User(id=2, name=张三2), key0=User(id=0, name=张三0)}
反序列化: 使用 TypeReference
{key1=User(id=1, name=张三1), key2=User(id=2, name=张三2), key0=User(id=0, name=张三0)}
2、自定义序列化和反序列化
- 序列化类继承抽象类
JsonSerializer
,需要的字段或类上
使用@JsonSerialize
注解 - 反序列化类继承抽象类
JsonDeserializer
,需要的字段或类上
使用@JsonDeserialize
注解
public class LongSerializer extends JsonSerializer<Long> {@Overridepublic void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {gen.writeString(value.toString());}
}@Data
public class User {@JsonSerialize(using = LongSerializer.class)private Long id;private String name;
}