1.概念与作用
1.1概念
序列化:
对象转换为字节序列的过程,本质上是将一个对象转换成二进制的byte[]数组
反序列化:
字节序列恢复为对象的过程
两种作用:
- 将对象序列化后永久的保存到硬盘中,通常是存在一个文件中;
- 在网络通信传递数据时需要;网络之间的通信均是使用二进制的形式互相通信,无论是发送还是接受,因为序列化和反序列化对网络通信至关重要。
2.对象序列化和反序列化
2.1JDK的序列化API
- java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
- java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
注意:
前提是实现Serializable接口; transient关键字修饰的字段不进行序列化; 静态字段不会序列化; Externalizable接口使用实现自定序列化;
2.2使用Jackson序列化
Jackson是SpringBoot自带的Json数据处理依赖包,但是其不依赖于Spring的库。
public class Human{
@JsonProperty("first_name")
private String firstName;
}
全局:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
某个字段:
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
@JsonIgnoreProperties({"age"})
public class Human{
@JsonIgnore
private String firstName;
private int age;
}
public class Human{
@JsonAlias({"first_name, name, firstName"})
private String firstName;
private int age;
}
在反序列化时,json字符串中有first_name
, name
或者是 firstName
均可以正确序列化成对象的字段firstName
2.3使用Jackson自定义序列化
序列化的过程通过get方法获取对象的属性数据,反序列化过程是先调用目标对象的无参构造函数生成一个对象,再通过对象的set方法为对象中的每一个属性进行赋值。因此通常一个对象想要序列化/反序列化则必须有get, set 和public的无参构造函数(java中不声明默认会有),也可以使用自定义的构造函数来进行反序列化。
1. 使用 @JsonCreator
public class CustomSerialization {
public static void main(String[] args) throws IOException {
Human human = new Human("zhangsan", 1, Lists.newArrayList("eat", "sleep"));
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(human);
System.out.println(jsonString);
Human humanFromSer = objectMapper.readValue(jsonString, Human.class);
System.out.println(humanFromSer);
}
public static class Human{
private String name;
private int sex;
private List<String> hobbies;
@JsonCreator
private Human(@JsonProperty("name") String name, @JsonProperty("sex") int sex, @JsonProperty("hobbies") List<String> hobbies){
this.name = name;
this.sex = sex;
this.hobbies = hobbies;
}
public String getName() {
return name;
}
public int getSex() {
return sex;
}
public List<String> getHobbies() {
return hobbies;
}
public void setName(String name) {
this.name = name;
}
public void setSex(int sex) {
this.sex = sex;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
}
}
Note:使用@JsonCreator时,其构造函数必须有@JsonProperty作为转换
@JsonCreator
和 @ConstructorProperties
作用使一致的,后者只能加在构造方法上,作为反序列化函数,后者使用起来比前者方便。不需要在构造函数中每个属性名前加@JsonProperty注解。
@ConstructorProperties({"name", "sex", "hobbies"})
private Human( String name, int sex, List<String> hobbies){
this.name = name;
this.sex = sex;
this.hobbies = hobbies;
}
Note: 该注解中的属性名称必须和构造函数中的属性名称保持一致,不然会解析失败报错
2.4 自定义序列化及反序列化类型转换器
1. 继承StdConverter类定义了一个Money类, 该类中定义一个final的字段, 这是为了不允许Json反序列化时调用set方法
public class CustomSerialization {
public static void main(String[] args) throws IOException {
Human human = new Human();
human.setName("zhangdan");
human.setSex(1);
human.setHobbies(Lists.newArrayList("eat", "sleep"));
Money money = new Money("USD");
human.setMonies(Lists.newArrayList(money));
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(human);
System.out.println(jsonString);
Human humanFromSer = objectMapper.readValue(jsonString, Human.class);
System.out.println(humanFromSer);
}
public static class Human{
private String name;
private int sex;
private List<String> hobbies;
@JsonSerialize(converter = MoneyConverter.class)
@JsonDeserialize(converter = MoneyDeserialize.class)
private List<Money> money;
public String getName() {
return name;
}
public int getSex() {
return sex;
}
public List<String> getHobbies() {
return hobbies;
}
public void setName(String name) {
this.name = name;
}
public void setSex(int sex) {
this.sex = sex;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public List<Money> getMoney() {
return money;
}
public void setMonies(List<Money> money) {
this.money = money;
}
}
public static class Money{
private final String type;
public Money(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
}
public class MoneyConverter extends StdConverter<List<CustomSerialization.Money>, List<String>> {
@Override
public List<String> convert(List<CustomSerialization.Money> money) {
return money.stream().map(CustomSerialization.Money::getType).collect(Collectors.toList());
}
}
public class MoneyDeserialize extends StdConverter<List<String>, List<CustomSerialization.Money>> {
@Override
public List<CustomSerialization.Money> convert(List<String> strings) {
return strings.stream().map(str ->new CustomSerialization.Money(str)).collect(Collectors.toList());
}
}
Note: 使用继承StdConverter的方式时, @JsonSerialize使用converter方法
@Data
public class Person {
private int age;
private String address;
private Man man;
private List<Man> men;
@Data
public static class Man{
@JsonSerialize(using = TimeSerializer.class)
@JsonDeserialize(using = TimeDeserializer.class)
private Instant time;
private Woman wife;
}
@Data
public static class Woman{
private String style;
private int beforeBoyFriends;
}
public static void main(String[] args) throws IOException {
Person person = new Person();
person.setAge(30);
person.setAddress("NewYork");
Woman woman = new Woman();
woman.setStyle("style");
woman.setBeforeBoyFriends(3);
Man man1 = new Man();
man1.setWife(woman);
man1.setTime(Instant.now());
person.setMan(man1);
Man man2 = new Man();
man2.setWife(woman);
man2.setTime(Instant.now());
person.setMen(Lists.newArrayList(man1, man2));
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(person);
System.out.println(jsonString);
Person personDemo= objectMapper.readValue(jsonString, Person.class);
System.out.println(personDemo.toString());
}
}
总结:这种自定义序列化的方式只支持某个字段的。 如果某个List存储的是一个多属性的对象,并且你想对该对象进行选择性或自定义序列化,此时你只能对该对象中的字段进行操作,而不能对其整个List对象进行操作。如果有大佬知道通知一下小编。