首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FastJson 笔记

FastJson 笔记

作者头像
Remember_Ray
发布2020-03-09 13:36:57
3.3K0
发布2020-03-09 13:36:57
举报
文章被收录于专栏:Ray学习笔记Ray学习笔记

现在主流的对象与 JSON 互转的工具很多,我们主要介绍今天的主角,阿里巴巴的开源库 - Fastjson。Fastjson是一个Java库,可用于将Java对象转换为其JSON表示。它还可用于将JSON字符串转换为等效的Java对象。Fastjson可以处理任意Java对象,包括您没有源代码的预先存在的对象。

FastJson 版本

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
</dependency>

FastJson 源码分析

JSONObject

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接口并调用接口中的方法完成的。

JSONArray

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

好了,接下来我们看最后一个,也是最重要的一个 JSON 类。之所以把这个放在最后,是因为这个类主要是实现转化用的,最后的数据获取,还是要通过上面的 JSONObject 和 JSONArray 来实现。

仔细观察这个类的方法,主要是实现 json 对象,json 对象数组,javabean 对象,json 字符串之间的相互转化。

JSON类之 toJSONString()

JSON类之 toJSONString() 方法,实现json对象转化为 json 字符串和 javabean 对象转化为json 字符串

该方法经过多次重载,但最终都是实现json对象转化为json字符串和javabean对象转化为json 字符串。

JSON类之 parseObject()

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类之JSONArray()方法,实现json字符串转化为json对象数组或List

与parseObject()方法类似,parseArray()将json字符串转化为json对象数组或转化成包含泛型的List

JSON类之 toJSON()

JSON类之toJSON()方法,实现javabean对象转化为json对象

该方法用的比较少,主要用于将javabean对象转化为json对象,内部通过Map,LinkedHashMap,HashMap等集合接口实现。

JSON类之toJavaObject()

JSON类之toJavaObject()方法,实现json对象转化为javabean对象

该方法也经过重载,通过 TypeReference 类和 Class 类反射来实现,主要讲 json 对象转化为 javabean 对象,用的也比较少。

至此,JSON 类中的方法也讲解的差不多了,下面给出 Java 实例来实现以上的各种转换。

总结

总结一下 fastjson 中三个类的用途和方法:

  • JSONObject:解析Json对象,获取对象中的值,通常是使用类中的get()方法
  • JSONArray:JSON对象数组,通常是通过迭代器取得其中的JSONObject,再利用JSONObeject的 get() 方法进行取值。
  • JSON:主要是实现 json 对象,json 对象数组,javabean对象,json字符串之间的相互转化。 转换之后取值还是按各自的方法进行。

FastJson 使用示例

JSON ——》 JSONObject

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

JSONObject ——》 JSON 字符串

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字符串数组转化为JSONArray,通过JSON的parseArray()方法。JSONArray本质上还是一个数组,对其进行遍历取得其中的JSONObject,然后再利用JSONObject的get()方法取得其中的值。有两种方式进行遍历

  • 方式一:通过jsonArray.size()获取JSONArray中元素的个数,再通过getJSONObject(index)获取相应位置的JSONObject,循环变量取得JSONArray中的JSONObject,再利用JSONObject的get()进行取值。
  • 方式二:通过jsonArray.iterator()获取迭代器
/**
 * 将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

JSONArray ——》 JSON 字符串

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格式字符串转换为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

复杂JSONObject ——》 JSON 字符串

用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"}]}

json字符串 ——》 JavaBean

@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字符串

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

/**
 * 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字符串数组

/**
 * 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_obj

对于复杂嵌套的JSON格式,利用JavaBean进行转换的时候要注意:

  1. 有几个JSONObject就定义几个JavaBean
  2. 内层的JSONObject对应的JavaBean作为外层JSONObject对应的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格式字符串

/**
 * 复杂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 特性

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 输出空值

在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 格式化打印

在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 处理日期

FastJson 处理日期的 API 非常简单

简单的 Date 类型

JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")

使用ISO-8601日期格式

JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);

全局修改日期格式

JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);

反序列化能够自动识别如下日期格式:

  • ISO-8601日期格式
  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • 毫秒数字
  • 毫秒数字字符串
  • .NET JSON日期格式
  • new Date(198293238)

简单示例

// 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 定制序列化

fastjson支持多种方式定制序列化。

  • 通过@JSONField定制序列化
  • 通过@JSONType定制序列化
  • 通过SerializeFilter定制序列化
  • 通过ParseProcess定制反序列化

@JSONField

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);

@JSONType

SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter,用于不同场景的定制序列化。

  • PropertyPreFilter 根据PropertyName判断是否序列化
  • PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
  • NameFilter 修改Key,如果需要修改Key,process返回值则可
  • ValueFilter 修改Value
  • BeforeFilter 序列化时在最前添加内容
  • AfterFilter 序列化时在最后添加内容

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);
}

FastJson 定制反序列化

通过ParseProcess定制反序列化。ParseProcess是编程扩展定制反序列化的接口。

fastjson 支持如下 ParseProcess:

  • ExtraProcessor 用于处理多余的字段
  • ExtraTypeProvider 用于处理多余字段时提供类型信息

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 类型了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • FastJson 版本
  • FastJson 源码分析
    • JSONObject
      • JSONArray
        • JSON
          • JSON类之 toJSONString()
          • JSON类之 parseObject()
          • JSON类之 JSONArray()
          • JSON类之 toJSON()
          • JSON类之toJavaObject()
        • 总结
        • FastJson 使用示例
          • JSON ——》 JSONObject
            • JSONObject ——》 JSON 字符串
              • JSON 字符串数组 ——》 JSONArray
                • JSONArray ——》 JSON 字符串
                  • 复杂JSON格式字符串 ——》 JSONObject
                    • 复杂JSONObject ——》 JSON 字符串
                      • json字符串 ——》 JavaBean
                        • JavaBean ——》 json字符串
                          • json字符串数组 ——》 JavaBean-List
                            • JavaBean-List ——》 json字符串数组
                              • 复杂嵌套json格式字符串 ——》JavaBean_obj
                                • JavaBean_obj ——》复杂嵌套json格式字符串
                                • FastJson 特性
                                  • FastJson 输出空值
                                    • FastJson 格式化打印
                                    • FastJson 处理日期
                                      • 简单的 Date 类型
                                        • 使用ISO-8601日期格式
                                          • 全局修改日期格式
                                            • 简单示例
                                            • FastJson 定制序列化
                                              • @JSONField
                                                • @JSONType
                                                • FastJson 定制反序列化
                                                领券
                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档