现在主流的对象与 JSON 互转的工具很多,我们主要介绍今天的主角,阿里巴巴的开源库 - Fastjson。Fastjson是一个Java库,可用于将Java对象转换为其JSON表示。它还可用于将JSON字符串转换为等效的Java对象。Fastjson可以处理任意Java对象,包括您没有源代码的预先存在的对象。
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler {
观察该类的继承与实现关系,不难发现,JSONObject 实现了 Map 接口,而 json 对象中的数据都是以”键:值”对形式出现,可以猜想, JSONObject 底层操作是由Map实现的。
类中主要是 get()
方法。因为 JSONObject 相当于json对象,所以该类中主要封装了各种get 方法,通过”键:值”对中的键来获取其对应的值。且方法的输入参数几乎皆为String类型,这是因为json对象中,”键:值”对的键都是String类型的。
看一下平时用到较多的 getString(String key)
方法
public String getString(String key) {
Object value = get(key);
if (value == null) {
return null;
}
return value.toString();
}
该方法输入参数为 String key(键),输出为String ,用于获取 json 对象中的字符串型数据。例如通过该方法获取 “name”:”Ray” 键值对中name这个键所对应的值Ray。
看其源码,可以发现,内部主要是由 get(key)
方法实现,这个方法如下:
public Object get(Object key) {
Object val = map.get(key);
if (val == null && key instanceof Number) {
val = map.get(key.toString());
}
return val;
}
发现内部主要由Map接口中的get()方法实现。
再去看 JSONObject 中另一个常用的方法 getInteger(String key)
该方法获取 json 对象中的整型数据,例如获取 “age:20” 键值对中age对应的整型数值20。
public Integer getInteger(String key) {
Object value = get(key);
return castToInt(value);
}
对比 getString(String key)
方法,两者极为相似,都是通过Map接口的 get()
方法实现。
再看几个其他的方法,也是由Map接口中的相应方法实现的,这里不再赘述。
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean containsKey(Object key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
return map.containsValue(value);
}
总结:JSONObject 对应 json 对象,通过各种形式的 get()
方法可以获取 json 对象中的数据,也可利用诸如 size()
,isEmpty()
等方法获取”键:值”对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {
观察 JSONArray 的继承与实现,并结合上面对 JSONObject 的分析,不难发现,其内部是有List接口中的方法来完成操作的。
首先来明确一点,因为JSONArray代表json对象数组,json数组对象中存储的是一个个json对象,所以类中的方法主要用于直接操作json对象。比如这其中的add(),remove(),containsAll()方法,对应于json对象的添加,删除与判断。
其内部主要有List接口中的对应方法来实现。
跟 JSONObject 一样,JSONArray 里面也有一些 get()
方法,不过都不常用,最有用的应该是 getJSONObject(int index)
方法,该方法用于获取 json 对象数组中指定位置的 JSONObject 对象,配合 size()
方法,可用于遍历 json 对象数组中的各个对象。
public JSONObject getJSONObject(int index) {
Object value = list.get(index);
if (value instanceof JSONObject) {
return (JSONObject) value;
}
if (value instanceof Map) {
return new JSONObject((Map) value);
}
return (JSONObject) toJSON(value);
}
在配合for循环,即可实现json对象数组的遍历,当然JSONArray中也实现了迭代器方法来遍历,这和List的遍历极为相似。
public Iterator<Object> iterator() {
return list.iterator();
}
通过遍历得到 JSONObject 对象,然后再利用 JSONObject 类中的 get()
方法,即可实现最终 json 数据的获取。
好了,接下来我们看最后一个,也是最重要的一个 JSON 类。之所以把这个放在最后,是因为这个类主要是实现转化用的,最后的数据获取,还是要通过上面的 JSONObject 和 JSONArray 来实现。
仔细观察这个类的方法,主要是实现 json 对象,json 对象数组,javabean 对象,json 字符串之间的相互转化。
JSON类之
toJSONString()
方法,实现json对象转化为 json 字符串和 javabean 对象转化为json 字符串
该方法经过多次重载,但最终都是实现json对象转化为json字符串和javabean对象转化为json 字符串。
JSON类之
parseObject()
方法,实现 json 字符串转换为 json 对象或 javabean 对象
该方法返回 JSONObject 对象,用于实现 json 字符串向 json 对象的转化,其内部调用了 parse()
方法,调用底层的 DefaultJSONParser
解析类进行转化,在转化失败时,抛出异常。
该方法不仅能实现 json 字符串向 json 对象的转化,经过重载之后,还能实现 json 字符串向 javabean 对象的转化
json字符串与javaBean之间的转换可以使用 TypeReference 这个类,也可以使用Class这个类。
Student stu1 = JSON.parseObject(jsonstr, new TypeReference<Student>(){});
Student stu2 = JSON.parseObject(jsonstr, Student.class);
JSON类之JSONArray()方法,实现json字符串转化为json对象数组或List
与parseObject()方法类似,parseArray()将json字符串转化为json对象数组或转化成包含泛型的List
JSON类之toJSON()方法,实现javabean对象转化为json对象
该方法用的比较少,主要用于将javabean对象转化为json对象,内部通过Map,LinkedHashMap,HashMap等集合接口实现。
JSON类之toJavaObject()方法,实现json对象转化为javabean对象
该方法也经过重载,通过 TypeReference 类和 Class 类反射来实现,主要讲 json 对象转化为 javabean 对象,用的也比较少。
至此,JSON 类中的方法也讲解的差不多了,下面给出 Java 实例来实现以上的各种转换。
总结一下 fastjson 中三个类的用途和方法:
get()
方法进行取值。用 JSON.parseObject() 方法即可将 JSON 字符串转化为 JSONObject 对象,利用JSONObject 中的 get()
方法来获取 JSONObject 中的相对应的键值对。
/**
* Json 字符串与 JSONObject 之间的转换
*/
public static void JsonStrToJSONObject() {
//json字符串-简单对象型,加\转义
String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";
JSONObject jsonObject = JSON.parseObject(JSON_OBJ_STR);
System.out.println("studentName: " + jsonObject.getString("studentName") + "\nStudentAge: " + jsonObject.getInteger("studentAge"));
}
输出结果
studentName: lily
StudentAge: 12
用 JSON.toJSONString()
方法即可将 JSONObject 对象转化为 JSON 字符串
/**
* 将JSONObject转换为JSON字符串,用 JSON.toJSONString()方法即可为JSONObject对象转换为JSON字符串
*/
public static void JSONObjectToJSONString() {
//json字符串-简单对象型,加\转义
String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";
JSONObject jsonObject = JSON.parseObject(JSON_OBJ_STR);
String str = JSON.toJSONString(jsonObject);
System.out.println(str);
}
输出结果
{"studentAge":12,"studentName":"lily"}
将JSON字符串数组转化为JSONArray,通过JSON的parseArray()方法。JSONArray本质上还是一个数组,对其进行遍历取得其中的JSONObject,然后再利用JSONObject的get()方法取得其中的值。有两种方式进行遍历
/**
* 将JSON字符串数组转化为JSONArray,通过JSON的parseArray()方法
*/
public static void JSONStringToJSONArray() {
String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12}," +
"{\"studentName\":\"lucy\",\"studentAge\":15}]";
JSONArray jsonArray = JSON.parseArray(JSON_ARRAY_STR);
// 遍历方式一
//int size = jsonArray.size();
//for (int i = 0; i < size; i++) {
// JSONObject jsonObject = jsonArray.getJSONObject(i);
// System.out.println("studentName: " + jsonObject.getString("studentName") + ", studentAge: " + jsonObject.getInteger("studentAge"));
//}
// 遍历方式二(推荐)
Iterator<Object> iterator = jsonArray.iterator();
while (iterator.hasNext()) {
JSONObject jsonObject = (JSONObject) iterator.next();
System.out.println("studentName: " + jsonObject.getString("studentName") + ", studentAge: " + jsonObject.getInteger("studentAge"));
}
}
输出结果
studentName: lily, studentAge: 12
studentName: lucy, studentAge: 15
用 JSON.toJSONString()
方法即可将 JSONArray 转化为 JSON 字符串
/**
* JSONArray到json字符串-数组类型的转换
*/
public static void JSONArrayToJSONString() {
String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12}," +
"{\"studentName\":\"lucy\",\"studentAge\":15}]";
JSONArray jsonArray = JSON.parseArray(JSON_ARRAY_STR);
String str = JSON.toJSONString(jsonArray);
System.out.println(str);
}
输出结果
[{"studentAge":12,"studentName":"lily"},{"studentAge":15,"studentName":"lucy"}]
将复杂JSON格式字符串转换为JSONObject,也是通过 JSON.parseObject()
/**
* 将复杂JSON格式字符串转换为JSONObject,也是通过JSON.parseObject(),可以取其中的部分
*/
public static void JSONStringToJSONObject() {
String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"students\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";
JSONObject jsonObject = JSON.parseObject(COMPLEX_JSON_STR);
// 获取简单对象
String teacherName = jsonObject.getString("teacherName");
Integer teacherAge = jsonObject.getInteger("teacherAge");
System.out.println("teacherName = " + teacherName);
System.out.println("teacherAge = " + teacherAge);
// 获取JSONObject对象
JSONObject course = jsonObject.getJSONObject("course");
// 获取JSONObject中的数据
String courseName = course.getString("courseName");
Integer code = course.getInteger("code");
System.out.println("courseName = " + courseName);
System.out.println("code = " + code);
// 获取JSONArray对象
JSONArray jsonArray = jsonObject.getJSONArray("students");
// 获取JSONArray中的数据
Iterator<Object> iterator = jsonArray.iterator();
while (iterator.hasNext()) {
JSONObject object = (JSONObject) iterator.next();
String studentName = object.getString("studentName");
Integer studentAge = object.getInteger("studentAge");
System.out.println("studentName = " + studentName);
System.out.println("studentAge = " + studentAge);
}
}
输出结果
teacherName = crystall
teacherAge = 27
courseName = english
code = 1270
studentName = lily
studentAge = 12
studentName = lucy
studentAge = 15
用JSON.toJSONString()方法即可将复杂JSONObject转化为JSON字符串
/**
* 复杂JSONObject到json字符串的转换
*/
public static void JSONObjectToJSON() {
String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"students\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";
JSONObject jsonObject = JSON.parseObject(COMPLEX_JSON_STR);
String str = JSON.toJSONString(jsonObject);
System.out.println(str);
}
输出结果
{"teacherAge":27,"teacherName":"crystall","course":{"courseName":"english","code":1270},"students":[{"studentAge":12,"studentName":"lily"},{"studentAge":15,"studentName":"lucy"}]}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String studentName;
private int studentAge;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
private String courseName;
private int code;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
private String teacherName;
private int teacherAge;
private Course course;
private List<Student> studentList;
}
Jason字符串转换为JavaBean有三种方式,推荐通过反射的方式。
/**
* json字符串-简单对象到JavaBean之间的转换
* 1、定义JavaBean对象
* 2、Jason字符串转换为JavaBean有三种方式,推荐通过反射的方式
*/
public static void JSONStringToJavaBean() {
//json字符串-简单对象型,加\转义
String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";
// 第一种方式
JSONObject jsonObject = JSON.parseObject(JSON_OBJ_STR);
String studentName = jsonObject.getString("studentName");
Integer studentAge = jsonObject.getInteger("studentAge");
Student student = new Student(studentName, studentAge);
System.out.println(student);
// 第二种方式,使用TypeReference<T>类,由于其构造方法使用protected进行修饰,故创建其子类
Student student1 = JSON.parseObject(JSON_OBJ_STR, new TypeReference<Student>() {});
System.out.println(student1);
// 第三种方式,通过反射,建议这种方式
Student student2 = JSON.parseObject(JSON_OBJ_STR, Student.class);
System.out.println(student2);
}
输出结果
Student(studentName=lily, studentAge=12)
JavaBean转换为Json字符串,也是通过JSON的toJSONString,不管是JSONObject、JSONArray还是JavaBean转为为JSON字符串都是通过JSON的toJSONString方法
/**
* JavaBean转换为Json字符串
*/
public static void JavaBeanToJsonString() {
Student lily = new Student("lily", 14);
String str = JSON.toJSONString(lily);
System.out.println(str);
}
输出结果
{"studentAge":14,"studentName":"lily"}
/**
* json字符串-数组类型到JavaBean-List的转换
*/
public static void JSONStrToJavaBeanList() {
String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12}," +
"{\"studentName\":\"lucy\",\"studentAge\":15}]";
List<Student> students = new ArrayList<>();
// 方式一:遍历
JSONArray jsonArray = JSON.parseArray(JSON_ARRAY_STR);
// 遍历 JSONArray
Iterator<Object> iterator = jsonArray.iterator();
while (iterator.hasNext()) {
JSONObject next = (JSONObject) iterator.next();
String studentName = next.getString("studentName");
Integer studentAge = next.getInteger("studentAge");
Student student = new Student(studentName, studentAge);
students.add(student);
}
System.out.println("students.size() = " + students.size());
// 方式二:使用TypeReference<T>类,由于其构造方法使用protected进行修饰,故创建其子类
List<Student> studentList = JSON.parseObject(JSON_ARRAY_STR, new TypeReference<List<Student>>() {});
System.out.println("studentList.size() = " + studentList.size());
// 方式三:使用反射
List<Student> studentList1 = JSON.parseArray(JSON_ARRAY_STR, Student.class);
System.out.println("studentList1.size() = " + studentList1.size());
}
输出结果
students.size() = 2
studentList.size() = 2
studentList1.size() = 2
/**
* JavaBean_List到json字符串-数组类型的转换,直接调用JSON.toJSONString()方法即可
*/
public static void JavaBeanListToJsonStr() {
String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12}," +
"{\"studentName\":\"lucy\",\"studentAge\":15}]";
List<Student> studentList = JSON.parseArray(JSON_ARRAY_STR, Student.class);
String str = JSON.toJSONString(studentList);
System.out.println(str);
}
输出结果
[{"studentAge":12,"studentName":"lily"},{"studentAge":15,"studentName":"lucy"}]
对于复杂嵌套的JSON格式,利用JavaBean进行转换的时候要注意:
/**
* 复杂json格式字符串到JavaBean_obj的转换
*/
public static void ComplexJsonStrToJavaBean() {
String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"studentList\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";
// 第一种方式,使用TypeReference<T>类,由于其构造方法使用protected进行修饰,故创建其子类
Teacher teacher = JSON.parseObject(COMPLEX_JSON_STR, new TypeReference<Teacher>() {});
System.out.println(teacher);
// 第二种方式,使用反射
Teacher teacher1 = JSON.parseObject(COMPLEX_JSON_STR, Teacher.class);
System.out.println(teacher1);
}
注意:属性名称应与 JSON 一一对应,否则为 null。
输出结果
Teacher(teacherName=crystall, teacherAge=27, course=Course(courseName=english, code=1270), studentList=[Student(studentName=lily, studentAge=12), Student(studentName=lucy, studentAge=15)])
/**
* 复杂JavaBean_obj到json格式字符串的转换
*/
public static void JavaBeanToComplexJSONStr() {
String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"studentList\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";
Teacher teacher = JSON.parseObject(COMPLEX_JSON_STR, Teacher.class);
String str = JSON.toJSONString(teacher);
System.out.println(str);
}
输出结果
{"course":{"code":1270,"courseName":"english"},"studentList":[{"studentAge":12,"studentName":"lily"},{"studentAge":15,"studentName":"lucy"}],"teacherAge":27,"teacherName":"crystall"}
FastJson的序列化特性定义在 com.alibaba.fastjson.serializer
包中,枚举类 SerializerFeature.java
。
可以通过设置多个特性到FastjsonConfig中全局使用,也可以在某个具体的JSON.writeJSONString时作为参数使用。
名称 | 含义 | 备注 |
---|---|---|
QuoteFieldNames | 输出key时是否使用双引号,默认为true | |
UseSingleQuotes | 使用单引号而不是双引号,默认为false | |
WriteMapNullValue | 是否输出Map值为null的字段,默认为false | |
WriteEnumUsingToString | 用枚举toString()值输出 | |
WriteEnumUsingName | 用枚举name()输出 | |
UseISO8601DateFormat | Date使用ISO8601格式输出,默认为false | |
WriteNullListAsEmpty | List字段如果为null,输出为[],而非null | |
WriteNullStringAsEmpty | 字符类型字段如果为null,输出为””,而非null | |
WriteNullNumberAsZero | 数值字段如果为null,输出为0,而非null | |
WriteNullBooleanAsFalse | Boolean字段如果为null,输出为false,而非null | |
SkipTransientField | 类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true | |
SortField | 按字段名称排序后输出。默认为false | |
WriteTabAsSpecial | 把\t做转义输出,默认为false | 不推荐 |
PrettyFormat | 结果是否格式化,默认为false | |
WriteClassName | 序列化时写入类型信息,默认为false。反序列化时需用到 | |
DisableCircularReferenceDetect | 消除对同一对象循环引用的问题,默认为false | |
WriteSlashAsSpecial | 对斜杠’/’进行转义 | |
BrowserCompatible | 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false | |
WriteDateUseDateFormat | 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat); | |
NotWriteRootClassName | ||
DisableCheckSpecialChar | 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false | |
BeanToArray | 将对象转为array输出 | |
WriteNonStringKeyAsString | 如果key不为String 则转换为String 比如Map的key为Integer | |
NotWriteDefaultValue | ||
BrowserSecure | ||
IgnoreNonFieldGetter | 忽略没有getter方法的属性 | |
WriteNonStringValueAsString | 不是String的字段写为String | |
IgnoreErrorGetter | 忽略掉getter方法出错的属性 | |
WriteBigDecimalAsPlain | 大精度值输出 value.toPlainString() : value.toString() | |
MapSortField | 对Map结果进行 TreeMap 排序(低版本中按字母排序) |
在fastjson中,缺省是不输出空值的。无论Map中的null和对象属性中的null,序列化的时候都会被忽略不输出,这样会减少产生文本的大小。但如果需要输出空值怎么做呢?
如果你需要输出空值,需要使用 SerializerFeature.WriteMapNullValue
属性 | 说明 |
---|---|
WriteNullListAsEmpty | 将集合类型字段的空值输出为 [] |
WriteNullStringAsEmpty | 将字符串类型字段的空值输出为 “” |
WriteNullNumberAsZero | 将数值类型字段的空值输出为 0 |
WriteNullBooleanAsFalse | 将布尔类型字段的空值输出为 false |
空值示例,可以同时选择多个:
Student student1 = new Student(1L, "Ray1");
Student student2 = new Student(2L, "Ray2");
Student student3 = new Student(3L, null);
Grade grade = new Grade();
grade.setId(0L);
grade.setName("admin");
grade.addStudent(student1);
grade.addStudent(student2);
grade.addStudent(student3);
// 序列化 - toJSONString 注意处理方式
String jsonStr = JSON.toJSONString(grade, SerializerFeature.WriteNullStringAsEmpty);
// 可以同时选择多个
//String jsonStr = JSON.toJSONString(grade, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullListAsEmpty);
System.out.println(jsonStr);
// 反序列化 - parseObject
Grade gradeObject = JSON.parseObject(jsonStr, Grade.class);
System.out.println(gradeObject);
输出结果
{"id":0,"name":"admin","studentList":[{"id":1,"name":"Ray1"},{"id":2,"name":"Ray2"},{"id":3}]}
Grade(id=0, name=admin, studentList=[Student(id=1, name=Ray1), Student(id=2, name=Ray2), Student(id=3, name=null)])
---------------- 使用前后对比 ----------------
{"id":0,"name":"admin","studentList":[{"id":1,"name":"Ray1"},{"id":2,"name":"Ray2"},{"id":3,"name":""}]}
Grade(id=0, name=admin, studentList=[Student(id=1, name=Ray1), Student(id=2, name=Ray2), Student(id=3, name=)])
在fastjson中,默认打印是格式化紧凑的,如果想打印格式化缩进的怎么做呢?
需要使用 SerializerFeature.PrettyFormat
String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"studentList\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";
Teacher teacher = JSON.parseObject(COMPLEX_JSON_STR, Teacher.class);
// 默认 紧凑
String str = JSON.toJSONString(teacher);
// 改为缩进
String newStr = JSON.toJSONString(teacher, SerializerFeature.PrettyFormat);
System.out.println(str);
System.out.println(newStr);
输出结果
{"course":{"code":1270,"courseName":"english"},"studentList":[{"studentAge":12,"studentName":"lily"},{"studentAge":15,"studentName":"lucy"}],"teacherAge":27,"teacherName":"crystall"}
{
"course":{
"code":1270,
"courseName":"english"
},
"studentList":[
{
"studentAge":12,
"studentName":"lily"
},
{
"studentAge":15,
"studentName":"lucy"
}
],
"teacherAge":27,
"teacherName":"crystall"
}
FastJson 处理日期的 API 非常简单
JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")
JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
反序列化能够自动识别如下日期格式:
// 1. 简单的 Date 类型处理
Date nowDate = new Date();
String nowDateStr = JSON.toJSONStringWithDateFormat(nowDate, "yyyy-MM-dd HH:mm:ss");
System.out.println("nowDateStr = " + nowDateStr);
// 2. 对象中的 Date 类型处理
Student2 student2 = new Student2(1L, "Ray", new Date());
// 序列化
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
String student2Json = JSON.toJSONString(student2, SerializerFeature.WriteDateUseDateFormat);
System.out.println(student2Json);
输出结果
nowDateStr = "2020-03-01 16:56:48"
{"birthday":"2020-03-01 16:56:48","id":1,"name":"Ray"}
虽然上面处理了单个的日期类型和全局的日期类型格式的配置,但是有时候我们需要的是对象中个别的日期类型差异化,并不一定是同一种格式的。那如何处理呢?接下来介绍 Fastjson 的定制序列化。
fastjson支持多种方式定制序列化。
1、 JSONField 部分注解介绍
public @interface JSONField {
// 配置序列化和反序列化的顺序,1.1.42版本之后才支持
int ordinal() default 0;
// 指定字段的名称
String name() default "";
// 指定字段的格式,对日期格式有用
String format() default "";
// 是否序列化
boolean serialize() default true;
// 是否反序列化
boolean deserialize() default true;
}
2、 可以把 @JSONField 配置在字段或者 getter/setter 方法上,例如:
public class VO {
@JSONField(name="ID")
private int id;
@JSONField(name="birthday",format="yyyy-MM-dd")
public Date date;
}
public class VO {
private int id;
@JSONField(name="ID")
public int getId() { return id;}
@JSONField(name="ID")
public void setId(int id) {this.id = id;}
}
注意:若属性是私有的,必须有set*方法。否则无法反序列化。
3、 使用format配置日期格式化
public class A {
// 配置date序列化和反序列使用yyyyMMdd日期格式
@JSONField(format="yyyyMMdd")
public Date date;
}
4、 使用serialize/deserialize指定字段不序列化
public class A {
@JSONField(serialize=false)
public Date date;
}
public class A {
@JSONField(deserialize=false)
public Date date;
}
5、 使用ordinal指定字段的顺序
缺省Fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。
public static class VO {
@JSONField(ordinal = 3)
private int f0;
@JSONField(ordinal = 2)
private int f1;
@JSONField(ordinal = 1)
private int f2;
}
6、 使用serializeUsing制定属性的序列化类
public static class Model {
@JSONField(serializeUsing = ModelValueSerializer.class)
public int value;
}
public static class ModelValueSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
int features) throws IOException {
Integer value = (Integer) object;
String text = value + "元";
serializer.write(text);
}
}
输出结果
Model model = new Model();
model.value = 100;
String json = JSON.toJSONString(model);
Assert.assertEquals("{\"value\":\"100元\"}", json);
SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter,用于不同场景的定制序列化。
1、 PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
public interface PropertyFilter extends SerializeFilter {
boolean apply(Object object, String propertyName, Object propertyValue);
}
可以通过扩展实现根据object或者属性名称或者属性值进行判断是否需要序列化。例如:
PropertyFilter filter = new PropertyFilter() {
public boolean apply(Object source, String name, Object value) {
if ("id".equals(name)) {
int id = ((Integer) value).intValue();
return id >= 100;
}
return false;
}
};
JSON.toJSONString(obj, filter); // 序列化的时候传入filter
2、 PropertyPreFilter 根据PropertyName判断是否序列化
和PropertyFilter不同只根据object和name进行判断,在调用getter之前,这样避免了getter调用可能存在的异常。
public interface PropertyPreFilter extends SerializeFilter {
boolean apply(JSONSerializer serializer, Object object, String name);
}
3、 NameFilter 序列化时修改Key
如果需要修改Key,process返回值则可。
public interface NameFilter extends SerializeFilter {
String process(Object object, String propertyName, Object propertyValue);
}
4、 ValueFilter 序列化时修改Value
public interface ValueFilter extends SerializeFilter {
Object process(Object object, String propertyName, Object propertyValue);
}
5、 BeforeFilter 序列化时在最前添加内容
在序列化对象的所有属性之前执行某些操作,例如调用 writeKeyValue 添加内容
public abstract class BeforeFilter implements SerializeFilter {
protected final void writeKeyValue(String key, Object value) { ... }
// 需要实现的抽象方法,在实现中调用writeKeyValue添加内容
public abstract void writeBefore(Object object);
}
6、 AfterFilter 序列化时在最后添加内容
在序列化对象的所有属性之后执行某些操作,例如调用 writeKeyValue 添加内容
public abstract class AfterFilter implements SerializeFilter {
protected final void writeKeyValue(String key, Object value) { ... }
// 需要实现的抽象方法,在实现中调用writeKeyValue添加内容
public abstract void writeAfter(Object object);
}
通过ParseProcess定制反序列化。ParseProcess是编程扩展定制反序列化的接口。
fastjson 支持如下 ParseProcess:
1、 使用 ExtraProcessor 处理多余字段
public static class VO {
private int id;
private Map<String, Object> attributes = new HashMap<String, Object>();
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public Map<String, Object> getAttributes() { return attributes;}
}
ExtraProcessor processor = new ExtraProcessor() {
public void processExtra(Object object, String key, Object value) {
VO vo = (VO) object;
vo.getAttributes().put(key, value);
}
};
VO vo = JSON.parseObject("{\"id\":123,\"name\":\"abc\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals("abc", vo.getAttributes().get("name"));
上面的代码中,VO 类中不存在 name 属性,但是可以通过 ExtraProcessor 将多余字段保存到 attributes 属性中。
2、 使用ExtraTypeProvider 为多余的字段提供类型
public static class VO {
private int id;
private Map<String, Object> attributes = new HashMap<String, Object>();
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public Map<String, Object> getAttributes() { return attributes;}
}
class MyExtraProcessor implements ExtraProcessor, ExtraTypeProvider {
public void processExtra(Object object, String key, Object value) {
VO vo = (VO) object;
vo.getAttributes().put(key, value);
}
public Type getExtraType(Object object, String key) {
if ("value".equals(key)) {
return int.class;
}
return null;
}
};
ExtraProcessor processor = new MyExtraProcessor();
VO vo = JSON.parseObject("{\"id\":123,\"value\":\"123456\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals(123456, vo.getAttributes().get("value"));
value 本应该是字符串类型的,通过 getExtraType 的处理变成 Integer 类型了。