FastJson 笔记

什么是fastjson

官方:fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

优点

  1. 速度快
  2. 使用广泛
  3. 测试完备
  4. 使用简单
  5. 功能完备

项目引入

maven项目引入fastjson相关包:

  1. <dependency>
  2. <groupId>com.alibaba</groupId>
  3. <artifactId>fastjson</artifactId>
  4. <version>1.2.56</version>
  5. </dependency>

JSON格式字符串与JSON对象之间的转换

该模块转自:高性能JSON框架之FastJson的简单使用

首先定义三个json格式的字符串

  1. //json字符串-简单对象型
  2. private static final String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";
  3. //json字符串-数组类型
  4. private static final String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]";
  5. //复杂格式json字符串
  6. private static final String COMPLEX_JSON_STR = "{\"teacherName\":\"crystall\",\"teacherAge\":27,\"course\":{\"courseName\":\"english\",\"code\":1270},\"students\":[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]}";

json字符串-简单对象型与JSONObject之间的转换

  1. /**
  2. * json字符串-简单对象型到JSONObject的转换
  3. */
  4. @Test
  5. public void testJSONStrToJSONObject() {
  6. JSONObject jsonObject = JSONObject.parseObject(JSON_OBJ_STR);
  7. System.out.println("studentName: " + jsonObject.getString("studentName") + ":" + " studentAge: "
  8. + jsonObject.getInteger("studentAge"));
  9. }
  10. /**
  11. * JSONObject到json字符串-简单对象型的转换
  12. */
  13. @Test
  14. public void testJSONObjectToJSONStr() {
  15. //已知JSONObject,目标要转换为json字符串
  16. JSONObject jsonObject = JSONObject.parseObject(JSON_OBJ_STR);
  17. // 第一种方式
  18. String jsonString = JSONObject.toJSONString(jsonObject);
  19. // 第二种方式
  20. //String jsonString = jsonObject.toJSONString();
  21. System.out.println(jsonString);
  22. }

json字符串(数组类型)与JSONArray之间的转换

  1. /**
  2. * json字符串-数组类型到JSONArray的转换
  3. */
  4. @Test
  5. public void testJSONStrToJSONArray() {
  6. JSONArray jsonArray = JSONArray.parseArray(JSON_ARRAY_STR);
  7. //遍历方式1
  8. int size = jsonArray.size();
  9. for (int i = 0; i < size; i++) {
  10. JSONObject jsonObject = jsonArray.getJSONObject(i);
  11. System.out.println("studentName: " + jsonObject.getString("studentName") + ":" + " studentAge: "
  12. + jsonObject.getInteger("studentAge"));
  13. }
  14. //遍历方式2
  15. for (Object obj : jsonArray) {
  16. JSONObject jsonObject = (JSONObject) obj;
  17. System.out.println("studentName: " + jsonObject.getString("studentName") + ":" + " studentAge: "
  18. + jsonObject.getInteger("studentAge"));
  19. }
  20. }
  21. /**
  22. * JSONArray到json字符串-数组类型的转换
  23. */
  24. @Test
  25. public void testJSONArrayToJSONStr() {
  26. //已知JSONArray,目标要转换为json字符串
  27. JSONArray jsonArray = JSONArray.parseArray(JSON_ARRAY_STR);
  28. //第一种方式
  29. String jsonString = JSONArray.toJSONString(jsonArray);
  30. // 第二种方式
  31. //String jsonString = jsonArray.toJSONString(jsonArray);
  32. System.out.println(jsonString);
  33. }

复杂json格式字符串与JSONObject之间的转换

  1. /**
  2. * 复杂json格式字符串到JSONObject的转换
  3. */
  4. @Test
  5. public void testComplexJSONStrToJSONObject() {
  6. JSONObject jsonObject = JSONObject.parseObject(COMPLEX_JSON_STR);
  7. String teacherName = jsonObject.getString("teacherName");
  8. Integer teacherAge = jsonObject.getInteger("teacherAge");
  9. System.out.println("teacherName: " + teacherName + " teacherAge: " + teacherAge);
  10. JSONObject jsonObjectcourse = jsonObject.getJSONObject("course");
  11. //获取JSONObject中的数据
  12. String courseName = jsonObjectcourse.getString("courseName");
  13. Integer code = jsonObjectcourse.getInteger("code");
  14. System.out.println("courseName: " + courseName + " code: " + code);
  15. JSONArray jsonArraystudents = jsonObject.getJSONArray("students");
  16. // JSONArray 转java的list 还可以如下
  17. // List list1 = jsonArraystudents.toJavaList(String.class);
  18. //遍历JSONArray
  19. for (Object object : jsonArraystudents) {
  20. JSONObject jsonObjectone = (JSONObject) object;
  21. String studentName = jsonObjectone.getString("studentName");
  22. Integer studentAge = jsonObjectone.getInteger("studentAge");
  23. System.out.println("studentName: " + studentName + " studentAge: " + studentAge);
  24. }
  25. }
  26. /**
  27. * 复杂JSONObject到json格式字符串的转换
  28. */
  29. @Test
  30. public void testJSONObjectToComplexJSONStr() {
  31. //复杂JSONObject,目标要转换为json字符串
  32. JSONObject jsonObject = JSONObject.parseObject(COMPLEX_JSON_STR);
  33. //第一种方式
  34. //String jsonString = JSONObject.toJSONString(jsonObject);
  35. //第二种方式
  36. String jsonString = jsonObject.toJSONString();
  37. System.out.println(jsonString);
  38. }

java对象序列化成json字符串

  1. // Lombok
  2. @Data
  3. class Test01 {
  4. String name, password, message;
  5. int age;
  6. }
  7. @Test
  8. public void test01() {
  9. Test01 test01=new Test01();
  10. test01.setAge(1);
  11. test01.setMessage("fastjson");
  12. test01.setName("meyoung");
  13. test01.setPassword("123");
  14. // 默认情况下 javaBean 映射成json object
  15. // {"age":1,"message":"fastjson","name":"meyoung","password":"123"}
  16. String jsonString = JSON.toJSONString(test01);
  17. log.info(jsonString);
  18. // 设置JavaBean 映射为json array
  19. // [1,"fastjson","meyoung","123"]
  20. String jsonArr = JSON.toJSONString(test01, SerializerFeature.BeanToArray);
  21. log.info(jsonArr);
  22. // 美化输出映射后的json
  23. String jsonPre = JSON.toJSONString(test01, SerializerFeature.PrettyFormat);
  24. log.info(jsonPre);
  25. }

上面都是默认情况的序列化,如果需要对输出的json格式的数据进行定制,例如key用单引号,String类型为空输出“”等等,当然上面的美化输出也是其中一种等等,你可以通过com.alibaba.fastjson.serializer.SerializerFeature枚举类来设定特性。

  1. String jsonPre = JSON.toJSONString(test01, SerializerFeature.PrettyFormat,
  2. SerializerFeature.WriteNullStringAsEmpty,
  3. SerializerFeature.UseSingleQuotes);

这块详细可以参考:fastjson SerializerFeature详解 - 孤天浪雨 - CSDN博客

json字符串反序列化成java对象

  1. @Test
  2. public void test02(){
  3. String string01 =" {\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\"}";
  4. Test01 test = JSON.parseObject(string01,Test01.class);
  5. log.info(test.getMessage());
  6. log.info(test.getName());
  7. log.info(test.getPassword());
  8. log.info(String.valueOf(test.getAge()));
  9. }
  10. @Test
  11. public void test02(){
  12. String string01 =" [{\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\"}]";
  13. List<Test01> test11 = JSON.parseArray(string01,Test01.class);
  14. Test01 test = test11.get(0);
  15. log.info(test.getMessage());
  16. log.info(test.getName());
  17. log.info(test.getPassword());
  18. log.info(String.valueOf(test.getAge()));
  19. }

泛型反序列化

TypeReference · alibaba/fastjson Wiki · GitHub
fastjson通过TypeReference来实现泛型的反序列化,以下是一个简单的例子程序。首先定义了BaseDTO用于所有DTO的父类,代码如下:

  1. public class BaseDTO implements Serializable {
  2. private static final long serialVersionUID = 2230553030766621644L;
  3. @Override
  4. public String toString() {
  5. return JSONObject.toJSONString(this);
  6. }
  7. }

RequestDTO用于抽像所有的请求DTO,里面有个泛型参数,代码如下:

  1. public final class RequestDTO<T extends BaseDTO> extends BaseDTO {
  2. private static final long serialVersionUID = -2780042604928728379L;
  3. /**
  4. * 调用方的名称
  5. */
  6. private String caller;
  7. /**
  8. * 请求参数
  9. */
  10. private T param;
  11. public String getCaller() {
  12. return caller;
  13. }
  14. public void setCaller(String caller) {
  15. this.caller = caller;
  16. }
  17. /**
  18. * 获取请求参数
  19. */
  20. public T getParam() {
  21. return param;
  22. }
  23. /**
  24. * 设置请求参数
  25. *
  26. * @param param 请求参数
  27. */
  28. public void setParam(T param) {
  29. this.param = param;
  30. }
  31. }

定义一个具体的业务对象, PersonDTO代码如下:

  1. @Data
  2. public class PersonDTO extends BaseDTO {
  3. private static final long serialVersionUID = 4637634512292751986L;
  4. private int id;
  5. private int age;
  6. private String name;
  7. }

测试:

  1. @Test
  2. public void test03(){
  3. RequestDTO<PersonDTO> requestDTO = new RequestDTO<PersonDTO>();
  4. requestDTO.setCaller("callerId");
  5. PersonDTO personDTO = new PersonDTO();
  6. personDTO.setAge(11);
  7. personDTO.setName("张三");
  8. requestDTO.setParam(personDTO);
  9. String jsonString = JSON.toJSONString(requestDTO);
  10. //{"caller":"callerId","param":{"age":11,"id":0,"name":"张三"}}
  11. System.out.println(jsonString);
  12. //这行是关键代码
  13. requestDTO = JSON.parseObject(jsonString, new TypeReference<RequestDTO<PersonDTO>>(){});
  14. // 张三
  15. System.out.println(requestDTO.getParam().getName());
  16. }

JSONField 介绍

fastjson提供了JSONField对序列化和反序列化进行定制。先看下 JSONField的部分源码:

  1. public @interface JSONField {
  2. /**
  3. * config encode/decode ordinal
  4. * @since 1.1.42
  5. * @return
  6. */
  7. // 配置序列化和反序列化的顺序
  8. int ordinal() default 0;
  9. // 指定字段的名称
  10. String name() default "";
  11. // 指定字段的格式,对日期格式有用
  12. String format() default "";
  13. // 是否序列化
  14. boolean serialize() default true;
  15. // 是否反序列化
  16. boolean deserialize() default true;
  17. //字段级别的SerializerFeature
  18. SerializerFeature[] serialzeFeatures() default {};
  19. Feature[] parseFeatures() default {};
  20. //给属性打上标签, 相当于给属性进行了分组
  21. String label() default "";
  22. boolean jsonDirect() default false;
  23. //制定属性的序列化类
  24. Class<?> serializeUsing() default Void.class;
  25. //制定属性的反序列化类
  26. Class<?> deserializeUsing() default Void.class;
  27. String[] alternateNames() default {};
  28. boolean unwrapped() default false;

JSONField注解的使用

注意:若属性是私有的,必须有set*方法。否则无法反序列化。

  1. // 配置在get*/set*上
  2. @JSONField(name="ID")
  3. public int getId() {return id;}
  4. // 配置在field上
  5. @JSONField(name="ID")
  6. public int id;
  7. // 配置date序列化和反序列使用日期格式
  8. @JSONField(format="yyyyMMdd")
  9. public Date date1;
  10. // 不序列化
  11. @JSONField(serialize=false)
  12. public Date date2;
  13. // 不反序列化
  14. @JSONField(deserialize=false)
  15. public Date date3;
  16. //缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。
  17. // 按ordinal排序
  18. @JSONField(ordinal = 2)
  19. private int f1;
  20. @JSONField(ordinal = 1)
  21. private int f2;

属性序列化和反序列化定制

JSONField提供的serializeUsing与deserializeUsing可以用于对特定属性字段的序列化与反序列化进行定制化。

假设我们现在有一个Users.java,代码详细如下:

  1. import lombok.Data;
  2. @Data
  3. class Users {
  4. String name, password, message;
  5. int age;
  6. boolean sex;
  7. }

这时我们定义的sex属性是boolean类型,这种明显不太合适,那么我们可以通过serializeUsing与deserializeUsing定制sex的序列化和反序列化。

serializeUsing定制序列化

我们新建个 UsersSerializer.java ,实现 ObjectSerializer 接口。 定制规则如果sex字段不为空或者为true则,序列化为男。

属性序列化定制
  1. public class UsersSerializer implements ObjectSerializer {
  2. // 序列化对sex属性额外处理
  3. @Override
  4. public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
  5. Boolean value = (Boolean) object;
  6. String text = "女";
  7. if (value != null && value.equals(true)) {
  8. text = "男";
  9. }
  10. serializer.write(text);
  11. }
  12. }

注册

我们在Users.java类中给sex属性加上JSONField注解,如下:

  1. @JSONField(serializeUsing = UsersSerializer.class)
  2. boolean sex;

使用
  1. @Test
  2. public void test01() {
  3. Users test01 = new Users();
  4. test01.setAge(1);
  5. test01.setMessage("fastjson");
  6. test01.setName("meyoung");
  7. test01.setPassword("123");
  8. test01.setSex(true);
  9. // {"age":1,"message":"fastjson","name":"meyoung","password":"123","sex":"男"}
  10. String jsonString = JSON.toJSONString(test01);
  11. log.info(jsonString);
  12. }

deserializeUsing定制反序列化

我们还是沿用上面的User.java类为例,定制反序列化定制的代码。

属性反序列化定制

我这里偷懒,直接用上面的 UsersSerializer.java 继续实现 ObjectDeserializer接口,并实现接口方法,最后ObjectDeserializer.java代码如下:

  1. public class UsersSerializer implements ObjectSerializer, ObjectDeserializer {
  2. // 序列化对sex属性额外处理
  3. @Override
  4. public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
  5. Boolean value = (Boolean) object;
  6. String text = "女";
  7. if (value != null && value.equals(true)) {
  8. text = "男";
  9. }
  10. serializer.write(text);
  11. }
  12. // 反序列化对sex属性额外处理
  13. @SuppressWarnings("unchecked")
  14. @Override
  15. public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
  16. String sex = parser.parseObject(String.class);
  17. if (sex.equals("男")) {
  18. return (T) Boolean.TRUE;
  19. } else {
  20. return (T) Boolean.FALSE;
  21. }
  22. }
  23. @Override
  24. public int getFastMatchToken() {
  25. return JSONToken.UNDEFINED;
  26. }
  27. }

注册

我们在Users.java类中给sex属性加上JSONField注解,如下:

  1. @JSONField(serializeUsing = UsersSerializer.class,deserializeUsing = UsersSerializer.class)
  2. boolean sex;

使用
  1. @Test
  2. public void test02() {
  3. String string01 = "{\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\",\"sex\":\"男\"}";
  4. Users test = JSON.parseObject(string01, Users.class);
  5. // true
  6. log.info(String.valueOf(test.sex));
  7. }

JSONType注解的使用

JSONType和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上。这里就不再demo,也可以查看官方文档学习:
JSONType_serializer · alibaba/fastjson Wiki · GitHub

自定义序列化之过滤器

fastjson通过SerializeFilter编程扩展的方式定制序列化fastjson支持以下SerializeFilter用于不同常景的定制序列化:

PropertyFilter

根据PropertyName和PropertyValue来判断是否序列化,接口定义如下:

  1. package com.alibaba.fastjson.serializer;
  2. /**
  3. * @author wenshao[szujobs@hotmail.com]
  4. */
  5. public interface PropertyFilter extends SerializeFilter {
  6. /**
  7. * @param object the owner of the property
  8. * @param name the name of the property
  9. * @param value the value of the property
  10. * @return true if the property will be included, false if to be filtered out
  11. * 根据 属性的name与value判断是否进行序列化
  12. */
  13. boolean apply(Object object, String name, Object value);
  14. }

DEMO:
Samples PropertyFilter · alibaba/fastjson Wiki · GitHub

PropertyPreFilter

根据PropertyName判断是否序列化

  1. package com.alibaba.fastjson.serializer;
  2. public interface PropertyPreFilter extends SerializeFilter {
  3. //根据 object与name判断是否进行序列化
  4. boolean apply(JSONSerializer serializer, Object object, String name);
  5. }

DEMO:
使用SimplePropertyPreFilter过滤属性 · alibaba/fastjson Wiki · GitHub

NameFilter

序列化时修改Key

  1. package com.alibaba.fastjson.serializer;
  2. public interface NameFilter extends SerializeFilter {
  3. //根据 name与value的值,返回json字段key的值
  4. String process(Object object, String name, Object value);
  5. }

ValueFilter

序列化时修改Value

  1. package com.alibaba.fastjson.serializer;
  2. public interface ValueFilter extends SerializeFilter {
  3. //根据name与value定制输出json的value
  4. Object process(Object object, String name, Object value);
  5. }

BeforeFilter

在序列化对象的所有属性之前执行某些操作

  1. package com.alibaba.fastjson.serializer;
  2. public abstract class BeforeFilter implements SerializeFilter {
  3. private static final ThreadLocal<JSONSerializer> serializerLocal = new ThreadLocal<JSONSerializer>();
  4. private static final ThreadLocal<Character> seperatorLocal = new ThreadLocal<Character>();
  5. private final static Character COMMA = Character.valueOf(',');
  6. final char writeBefore(JSONSerializer serializer, Object object, char seperator) {
  7. serializerLocal.set(serializer);
  8. seperatorLocal.set(seperator);
  9. writeBefore(object);
  10. serializerLocal.set(null);
  11. return seperatorLocal.get();
  12. }
  13. protected final void writeKeyValue(String key, Object value) {
  14. JSONSerializer serializer = serializerLocal.get();
  15. char seperator = seperatorLocal.get();
  16. serializer.writeKeyValue(seperator, key, value);
  17. if (seperator != ',') {
  18. seperatorLocal.set(COMMA);
  19. }
  20. }
  21. //需要实现的方法,在实际实现中可以调用writeKeyValue增加json的内容
  22. public abstract void writeBefore(Object object);
  23. }

AfterFilter

在序列化对象的所有属性之后执行某些操作

  1. package com.alibaba.fastjson.serializer;
  2. /**
  3. * @since 1.1.35
  4. */
  5. public abstract class AfterFilter implements SerializeFilter {
  6. private static final ThreadLocal<JSONSerializer> serializerLocal = new ThreadLocal<JSONSerializer>();
  7. private static final ThreadLocal<Character> seperatorLocal = new ThreadLocal<Character>();
  8. private final static Character COMMA = Character.valueOf(',');
  9. final char writeAfter(JSONSerializer serializer, Object object, char seperator) {
  10. serializerLocal.set(serializer);
  11. seperatorLocal.set(seperator);
  12. writeAfter(object);
  13. serializerLocal.set(null);
  14. return seperatorLocal.get();
  15. }
  16. protected final void writeKeyValue(String key, Object value) {
  17. JSONSerializer serializer = serializerLocal.get();
  18. char seperator = seperatorLocal.get();
  19. serializer.writeKeyValue(seperator, key, value);
  20. if (seperator != ',') {
  21. seperatorLocal.set(COMMA);
  22. }
  23. }
  24. //子类需要实现的方法,实际使用的时候可以调用writeKeyValue增加内容
  25. public abstract void writeAfter(Object object);
  26. }

LabelFilter

根据 JsonField配置的label来判断是否进行输出

  1. package com.alibaba.fastjson.serializer;
  2. //根据 JsonField配置的label来判断是否进行输出
  3. public interface LabelFilter extends SerializeFilter {
  4. boolean apply(String label);
  5. }

参考文档

JSONField · alibaba/fastjson Wiki · GitHub
JSON最佳实践 | kimmking’s blog
fastjson SerializerFeature详解 - 孤天浪雨 - CSDN博客
fastjson详解 - 简书