源碼地址:
https://github.com/zhouweixin/serializablejava
準備了兩個類, 教師類和學生類, 其中一個學生只有一個教師
這裏省略了構造方法和setter, getter方法git
Teacher.javagithub
public class Teacher { private String name; private Integer age; }
Student.javashell
package org.zwx; public class Student { private String name; private Integer age; private Sex sex; private String fatherName; private Date bornTime; private Teacher teacher; }
Sex.java數據庫
public enum Sex { MALE("男"), FEMALE("女"); private String name; Sex(String name) { this.name = name; } public String getName() { return name; } }
本示例是基於gradle的, 從maven中心倉庫中選擇了2.11.2版本的jackson-databindjson
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.2'
public void testSerializable() throws IOException { Student student1 = new Student("小明", 18, Sex.MALE, "王富貴", new Date(), new Teacher("李老師", 40)); Student student2 = new Student("小花", 16, Sex.FEMALE, "錢不少", new Date(), new Teacher("趙老師", 38)); List<Student> students = new ArrayList<>(); students.add(student1); students.add(student2); ObjectMapper mapper = new ObjectMapper(); String s = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(students); System.out.println(s); }
[ { "name" : "小明", "age" : 18, "sex" : "MALE", "fatherName" : "王富貴", "bornTime" : 1599996926917, "teacher" : { "name" : "李老師", "age" : 40 } }, { "name" : "小花", "age" : 16, "sex" : "FEMALE", "fatherName" : "錢不少", "bornTime" : 1599996926917, "teacher" : { "name" : "趙老師", "age" : 38 } } ]
[{"name":"小明","age":18,"sex":"MALE","fatherName":"王富貴","bornTime":1599997061097,"teacher":{"name":"李老師","age":40}},{"name":"小花","age":16,"sex":"FEMALE","fatherName":"錢不少","bornTime":1599997061097,"teacher":{"name":"趙老師","age":38}}]
假如須要將序列化的json由駝峯命名修改成下劃線命名, 如fatherName修改成father_name數組
只須要在字段fatherName上用註解JsonProperty配置網絡
@JsonProperty("father_name") private String fatherName; @JsonProperty("born_time") private Date bornTime;
[ { "name" : "小明", "age" : 18, "sex" : "MALE", "teacher" : { "name" : "李老師", "age" : 40 }, "father_name" : "王富貴", "born_time" : 1599997157609 }, { "name" : "小花", "age" : 16, "sex" : "FEMALE", "teacher" : { "name" : "趙老師", "age" : 38 }, "father_name" : "錢不少", "born_time" : 1599997157610 } ]
當前bornTime的格式爲unix時間戮, 可讀性很是差app
現修改成yyyy-MM-dd HH:mm:ss
並設置時區爲東八區maven
示例代碼
@JsonProperty("born_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date bornTime;
結果
[ { "name" : "小明", "age" : 18, "sex" : "MALE", "teacher" : { "name" : "李老師", "age" : 40 }, "father_name" : "王富貴", "born_time" : "2020-09-13 19:50:47" }, { "name" : "小花", "age" : 16, "sex" : "FEMALE", "teacher" : { "name" : "趙老師", "age" : 38 }, "father_name" : "錢不少", "born_time" : "2020-09-13 19:50:47" } ]
只須要爲Sex添加一個方法getOrdinal, 並添加註解JsonValue便可
示例代碼
@JsonValue public String getOrdinal() { return name; }
示例結果
[ { "name" : "小明", "age" : 18, "sex" : "男", "teacher" : { "name" : "李老師", "age" : 40 }, "father_name" : "王富貴", "born_time" : "2020-09-13 19:57:47" }, { "name" : "小花", "age" : 16, "sex" : "女", "teacher" : { "name" : "趙老師", "age" : 38 }, "father_name" : "錢不少", "born_time" : "2020-09-13 19:57:47" } ]
有些場景喜歡用0和1等序號設置男女, 即枚舉的序號: 0表示男, 1表示女
此時須要修改Set的getOrdinal方法
示例代碼
@JsonValue public int getOrdinal() { return super.ordinal(); }
示例結果
[ { "name" : "小明", "age" : 18, "sex" : 0, "teacher" : { "name" : "李老師", "age" : 40 }, "father_name" : "王富貴", "born_time" : "2020-09-13 20:01:44" }, { "name" : "小花", "age" : 16, "sex" : 1, "teacher" : { "name" : "趙老師", "age" : 38 }, "father_name" : "錢不少", "born_time" : "2020-09-13 20:01:44" } ]
如前面提到的結果所示, teacher的兩個屬性並不在student的第一層,
有時可能會更深的層次, 使用起來不太友好
如何用teacher_name和teacher_age兩個屬性代替teacher呢?
Student.java
@JsonUnwrapped private Teacher teacher;
Teacher.java
@JsonProperty("teacher_name") private String name; @JsonProperty("teacher_age") private Integer age;
[ { "name" : "小明", "age" : 18, "sex" : 0, "teacher_name" : "李老師", "teacher_age" : 40, "father_name" : "王富貴", "born_time" : "2020-09-13 20:21:53" }, { "name" : "小花", "age" : 16, "sex" : 1, "teacher_name" : "趙老師", "teacher_age" : 38, "father_name" : "錢不少", "born_time" : "2020-09-13 20:21:53" } ]
假如須要將年齡調整爲理論學齡, 即將年齡減去7, 獲得理論學齡, 如何操做呢?
AgeSerializer.java
public class AgeSerializer extends StdSerializer<Integer> { protected AgeSerializer() { super(Integer.class); } @Override public void serialize(Integer value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeNumber(value - 7); } }
Student.java
@JsonSerialize(using = AgeSerializer.class) private Integer age;
[ { "name" : "小明", "age" : 11, "sex" : 0, "teacher_name" : "李老師", "teacher_age" : 40, "father_name" : "王富貴", "born_time" : "2020-09-13 20:31:59" }, { "name" : "小花", "age" : 9, "sex" : 1, "teacher_name" : "趙老師", "teacher_age" : 38, "father_name" : "錢不少", "born_time" : "2020-09-13 20:31:59" } ]
示例代碼
public void testDeserializable() throws JsonProcessingException { String s = "{\"name\":\"小明\",\"age\":11,\"sex\":0,\"teacher_name\":\"李老師\",\"teacher_age\":40,\"father_name\":\"王富貴\",\"born_time\":\"2020-09-13 20:46:10\"}"; ObjectMapper mapper = new ObjectMapper(); Student student = mapper.readValue(s, Student.class); System.out.println(student); }
示例結果
Student{name='小明', age=11, sex=MALE, fatherName='王富貴', bornTime=Sun Sep 13 20:46:10 CST 2020, teacher=Teacher{name='李老師', age=40}}
分析
示例代碼
public void testDeserializableStudents() throws JsonProcessingException { String s = "[{\"name\":\"小明\",\"age\":11,\"sex\":0,\"teacher_name\":\"李老師\",\"teacher_age\":40,\"father_name\":\"王富貴\",\"born_time\":\"2020-09-13 20:51:31\"},{\"name\":\"小花\",\"age\":9,\"sex\":1,\"teacher_name\":\"趙老師\",\"teacher_age\":38,\"father_name\":\"錢不少\",\"born_time\":\"2020-09-13 20:51:31\"}]"; ObjectMapper mapper = new ObjectMapper(); Student[] students = mapper.readValue(s, Student[].class); for (Student student : students) { System.out.println(student); } }
示例結果
Student{name='小明', age=11, sex=MALE, fatherName='王富貴', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='李老師', age=40}} Student{name='小花', age=9, sex=FEMALE, fatherName='錢不少', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='趙老師', age=38}}
分析
從10.2節及10.3的現象中能夠看出來, 僅僅自定義的序列化器會致使序列化的過程是正常的, 反序列化的過程仍然是默認邏輯, 有時候會致使意想不到的結果
遇到此場景, 能夠考慮自定義反序列化器
示例代碼
AgeDeserializer.java
public class AgeDeserializer extends JsonDeserializer<Integer> { @Override public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { return p.getIntValue() + 7; } }
Student.java
@JsonSerialize(using = AgeSerializer.class) @JsonDeserialize(using = AgeDeserializer.class) private Integer age;
示例結果
Student{name='小明', age=18, sex=MALE, fatherName='王富貴', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='李老師', age=40}} Student{name='小花', age=16, sex=FEMALE, fatherName='錢不少', bornTime=Sun Sep 13 20:51:31 CST 2020, teacher=Teacher{name='趙老師', age=38}}
該註解使用在實體類上, 格式@JsonInclude(value = JsonInclude.Include.NON_DEFAULT)
其中, Include有7種參數, 功能對好比下
參數 | 功能 | 備註 |
---|---|---|
Include.ALWAYS | 屬性老是序列化(須要有get方法) | 默認值 |
Include.NON_DEFAULT | 屬性爲默認值不序列化 | 如: int:0, bool:false |
Include.NON_EMPTY | 屬性爲空("")或null不序列化 | |
Include.NON_NULL | 屬性爲null不序列化 | |
Include.CUSTOM | ||
Include.USE_DEFAULTS | ||
Include.NON_ABSENT |
Student.java
@JsonInclude(value = JsonInclude.Include.NON_DEFAULT) public class Student {
public void testNonDefault() throws IOException { Student student = new Student("", 0, null, null, null, null); ObjectMapper mapper = new ObjectMapper(); String s = mapper.writeValueAsString(student); System.out.println(s); }
{ "name" : "", "age" : -7 }