FastJson 笔记
什么是fastjson
官方:fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
优点
- 速度快
- 使用广泛
- 测试完备
- 使用简单
- 功能完备
项目引入
maven项目引入fastjson相关包:
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.56</version></dependency>
JSON格式字符串与JSON对象之间的转换
该模块转自:高性能JSON框架之FastJson的简单使用
首先定义三个json格式的字符串
//json字符串-简单对象型private static final String JSON_OBJ_STR = "{\"studentName\":\"lily\",\"studentAge\":12}";//json字符串-数组类型private static final String JSON_ARRAY_STR = "[{\"studentName\":\"lily\",\"studentAge\":12},{\"studentName\":\"lucy\",\"studentAge\":15}]";//复杂格式json字符串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之间的转换
/*** json字符串-简单对象型到JSONObject的转换*/@Testpublic void testJSONStrToJSONObject() {JSONObject jsonObject = JSONObject.parseObject(JSON_OBJ_STR);System.out.println("studentName: " + jsonObject.getString("studentName") + ":" + " studentAge: "+ jsonObject.getInteger("studentAge"));}/*** JSONObject到json字符串-简单对象型的转换*/@Testpublic void testJSONObjectToJSONStr() {//已知JSONObject,目标要转换为json字符串JSONObject jsonObject = JSONObject.parseObject(JSON_OBJ_STR);// 第一种方式String jsonString = JSONObject.toJSONString(jsonObject);// 第二种方式//String jsonString = jsonObject.toJSONString();System.out.println(jsonString);}
json字符串(数组类型)与JSONArray之间的转换
/*** json字符串-数组类型到JSONArray的转换*/@Testpublic void testJSONStrToJSONArray() {JSONArray jsonArray = JSONArray.parseArray(JSON_ARRAY_STR);//遍历方式1int 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"));}//遍历方式2for (Object obj : jsonArray) {JSONObject jsonObject = (JSONObject) obj;System.out.println("studentName: " + jsonObject.getString("studentName") + ":" + " studentAge: "+ jsonObject.getInteger("studentAge"));}}/*** JSONArray到json字符串-数组类型的转换*/@Testpublic void testJSONArrayToJSONStr() {//已知JSONArray,目标要转换为json字符串JSONArray jsonArray = JSONArray.parseArray(JSON_ARRAY_STR);//第一种方式String jsonString = JSONArray.toJSONString(jsonArray);// 第二种方式//String jsonString = jsonArray.toJSONString(jsonArray);System.out.println(jsonString);}
复杂json格式字符串与JSONObject之间的转换
/*** 复杂json格式字符串到JSONObject的转换*/@Testpublic void testComplexJSONStrToJSONObject() {JSONObject jsonObject = JSONObject.parseObject(COMPLEX_JSON_STR);String teacherName = jsonObject.getString("teacherName");Integer teacherAge = jsonObject.getInteger("teacherAge");System.out.println("teacherName: " + teacherName + " teacherAge: " + teacherAge);JSONObject jsonObjectcourse = jsonObject.getJSONObject("course");//获取JSONObject中的数据String courseName = jsonObjectcourse.getString("courseName");Integer code = jsonObjectcourse.getInteger("code");System.out.println("courseName: " + courseName + " code: " + code);JSONArray jsonArraystudents = jsonObject.getJSONArray("students");// JSONArray 转java的list 还可以如下// List list1 = jsonArraystudents.toJavaList(String.class);//遍历JSONArrayfor (Object object : jsonArraystudents) {JSONObject jsonObjectone = (JSONObject) object;String studentName = jsonObjectone.getString("studentName");Integer studentAge = jsonObjectone.getInteger("studentAge");System.out.println("studentName: " + studentName + " studentAge: " + studentAge);}}/*** 复杂JSONObject到json格式字符串的转换*/@Testpublic void testJSONObjectToComplexJSONStr() {//复杂JSONObject,目标要转换为json字符串JSONObject jsonObject = JSONObject.parseObject(COMPLEX_JSON_STR);//第一种方式//String jsonString = JSONObject.toJSONString(jsonObject);//第二种方式String jsonString = jsonObject.toJSONString();System.out.println(jsonString);}
java对象序列化成json字符串
// Lombok@Dataclass Test01 {String name, password, message;int age;}@Testpublic void test01() {Test01 test01=new Test01();test01.setAge(1);test01.setMessage("fastjson");test01.setName("meyoung");test01.setPassword("123");// 默认情况下 javaBean 映射成json object// {"age":1,"message":"fastjson","name":"meyoung","password":"123"}String jsonString = JSON.toJSONString(test01);log.info(jsonString);// 设置JavaBean 映射为json array// [1,"fastjson","meyoung","123"]String jsonArr = JSON.toJSONString(test01, SerializerFeature.BeanToArray);log.info(jsonArr);// 美化输出映射后的jsonString jsonPre = JSON.toJSONString(test01, SerializerFeature.PrettyFormat);log.info(jsonPre);}
上面都是默认情况的序列化,如果需要对输出的json格式的数据进行定制,例如key用单引号,String类型为空输出“”等等,当然上面的美化输出也是其中一种等等,你可以通过com.alibaba.fastjson.serializer.SerializerFeature枚举类来设定特性。
String jsonPre = JSON.toJSONString(test01, SerializerFeature.PrettyFormat,SerializerFeature.WriteNullStringAsEmpty,SerializerFeature.UseSingleQuotes);
这块详细可以参考:fastjson SerializerFeature详解 - 孤天浪雨 - CSDN博客
json字符串反序列化成java对象
@Testpublic void test02(){String string01 =" {\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\"}";Test01 test = JSON.parseObject(string01,Test01.class);log.info(test.getMessage());log.info(test.getName());log.info(test.getPassword());log.info(String.valueOf(test.getAge()));}@Testpublic void test02(){String string01 =" [{\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\"}]";List<Test01> test11 = JSON.parseArray(string01,Test01.class);Test01 test = test11.get(0);log.info(test.getMessage());log.info(test.getName());log.info(test.getPassword());log.info(String.valueOf(test.getAge()));}
泛型反序列化
TypeReference · alibaba/fastjson Wiki · GitHub
fastjson通过TypeReference来实现泛型的反序列化,以下是一个简单的例子程序。首先定义了BaseDTO用于所有DTO的父类,代码如下:
public class BaseDTO implements Serializable {private static final long serialVersionUID = 2230553030766621644L;@Overridepublic String toString() {return JSONObject.toJSONString(this);}}
RequestDTO用于抽像所有的请求DTO,里面有个泛型参数,代码如下:
public final class RequestDTO<T extends BaseDTO> extends BaseDTO {private static final long serialVersionUID = -2780042604928728379L;/*** 调用方的名称*/private String caller;/*** 请求参数*/private T param;public String getCaller() {return caller;}public void setCaller(String caller) {this.caller = caller;}/*** 获取请求参数*/public T getParam() {return param;}/*** 设置请求参数** @param param 请求参数*/public void setParam(T param) {this.param = param;}}
定义一个具体的业务对象, PersonDTO代码如下:
@Datapublic class PersonDTO extends BaseDTO {private static final long serialVersionUID = 4637634512292751986L;private int id;private int age;private String name;}
测试:
@Testpublic void test03(){RequestDTO<PersonDTO> requestDTO = new RequestDTO<PersonDTO>();requestDTO.setCaller("callerId");PersonDTO personDTO = new PersonDTO();personDTO.setAge(11);personDTO.setName("张三");requestDTO.setParam(personDTO);String jsonString = JSON.toJSONString(requestDTO);//{"caller":"callerId","param":{"age":11,"id":0,"name":"张三"}}System.out.println(jsonString);//这行是关键代码requestDTO = JSON.parseObject(jsonString, new TypeReference<RequestDTO<PersonDTO>>(){});// 张三System.out.println(requestDTO.getParam().getName());}
JSONField 介绍
fastjson提供了JSONField对序列化和反序列化进行定制。先看下 JSONField的部分源码:
public @interface JSONField {/*** config encode/decode ordinal* @since 1.1.42* @return*/// 配置序列化和反序列化的顺序int ordinal() default 0;// 指定字段的名称String name() default "";// 指定字段的格式,对日期格式有用String format() default "";// 是否序列化boolean serialize() default true;// 是否反序列化boolean deserialize() default true;//字段级别的SerializerFeatureSerializerFeature[] serialzeFeatures() default {};Feature[] parseFeatures() default {};//给属性打上标签, 相当于给属性进行了分组String label() default "";boolean jsonDirect() default false;//制定属性的序列化类Class<?> serializeUsing() default Void.class;//制定属性的反序列化类Class<?> deserializeUsing() default Void.class;String[] alternateNames() default {};boolean unwrapped() default false;
JSONField注解的使用
注意:若属性是私有的,必须有set*方法。否则无法反序列化。
// 配置在get*/set*上@JSONField(name="ID")public int getId() {return id;}// 配置在field上@JSONField(name="ID")public int id;// 配置date序列化和反序列使用日期格式@JSONField(format="yyyyMMdd")public Date date1;// 不序列化@JSONField(serialize=false)public Date date2;// 不反序列化@JSONField(deserialize=false)public Date date3;//缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。// 按ordinal排序@JSONField(ordinal = 2)private int f1;@JSONField(ordinal = 1)private int f2;
属性序列化和反序列化定制
JSONField提供的serializeUsing与deserializeUsing可以用于对特定属性字段的序列化与反序列化进行定制化。
假设我们现在有一个Users.java,代码详细如下:
import lombok.Data;@Dataclass Users {String name, password, message;int age;boolean sex;}
这时我们定义的sex属性是boolean类型,这种明显不太合适,那么我们可以通过serializeUsing与deserializeUsing定制sex的序列化和反序列化。
serializeUsing定制序列化
我们新建个 UsersSerializer.java ,实现 ObjectSerializer 接口。 定制规则如果sex字段不为空或者为true则,序列化为男。
属性序列化定制
public class UsersSerializer implements ObjectSerializer {// 序列化对sex属性额外处理@Overridepublic void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {Boolean value = (Boolean) object;String text = "女";if (value != null && value.equals(true)) {text = "男";}serializer.write(text);}}
注册
我们在Users.java类中给sex属性加上JSONField注解,如下:
@JSONField(serializeUsing = UsersSerializer.class)boolean sex;
使用
@Testpublic void test01() {Users test01 = new Users();test01.setAge(1);test01.setMessage("fastjson");test01.setName("meyoung");test01.setPassword("123");test01.setSex(true);// {"age":1,"message":"fastjson","name":"meyoung","password":"123","sex":"男"}String jsonString = JSON.toJSONString(test01);log.info(jsonString);}
deserializeUsing定制反序列化
我们还是沿用上面的User.java类为例,定制反序列化定制的代码。
属性反序列化定制
我这里偷懒,直接用上面的 UsersSerializer.java 继续实现 ObjectDeserializer接口,并实现接口方法,最后ObjectDeserializer.java代码如下:
public class UsersSerializer implements ObjectSerializer, ObjectDeserializer {// 序列化对sex属性额外处理@Overridepublic void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {Boolean value = (Boolean) object;String text = "女";if (value != null && value.equals(true)) {text = "男";}serializer.write(text);}// 反序列化对sex属性额外处理@SuppressWarnings("unchecked")@Overridepublic <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {String sex = parser.parseObject(String.class);if (sex.equals("男")) {return (T) Boolean.TRUE;} else {return (T) Boolean.FALSE;}}@Overridepublic int getFastMatchToken() {return JSONToken.UNDEFINED;}}
注册
我们在Users.java类中给sex属性加上JSONField注解,如下:
@JSONField(serializeUsing = UsersSerializer.class,deserializeUsing = UsersSerializer.class)boolean sex;
使用
@Testpublic void test02() {String string01 = "{\"age\":1,\"message\":\"fastjson\",\"name\":\"meyoung\",\"password\":\"123\",\"sex\":\"男\"}";Users test = JSON.parseObject(string01, Users.class);// truelog.info(String.valueOf(test.sex));}
JSONType注解的使用
JSONType和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上。这里就不再demo,也可以查看官方文档学习:
JSONType_serializer · alibaba/fastjson Wiki · GitHub
自定义序列化之过滤器
fastjson通过SerializeFilter编程扩展的方式定制序列化fastjson支持以下SerializeFilter用于不同常景的定制序列化:
PropertyFilter
根据PropertyName和PropertyValue来判断是否序列化,接口定义如下:
package com.alibaba.fastjson.serializer;/*** @author wenshao[szujobs@hotmail.com]*/public interface PropertyFilter extends SerializeFilter {/*** @param object the owner of the property* @param name the name of the property* @param value the value of the property* @return true if the property will be included, false if to be filtered out* 根据 属性的name与value判断是否进行序列化*/boolean apply(Object object, String name, Object value);}
DEMO:
Samples PropertyFilter · alibaba/fastjson Wiki · GitHub
PropertyPreFilter
根据PropertyName判断是否序列化
package com.alibaba.fastjson.serializer;public interface PropertyPreFilter extends SerializeFilter {//根据 object与name判断是否进行序列化boolean apply(JSONSerializer serializer, Object object, String name);}
DEMO:
使用SimplePropertyPreFilter过滤属性 · alibaba/fastjson Wiki · GitHub
NameFilter
序列化时修改Key
package com.alibaba.fastjson.serializer;public interface NameFilter extends SerializeFilter {//根据 name与value的值,返回json字段key的值String process(Object object, String name, Object value);}
ValueFilter
序列化时修改Value
package com.alibaba.fastjson.serializer;public interface ValueFilter extends SerializeFilter {//根据name与value定制输出json的valueObject process(Object object, String name, Object value);}
BeforeFilter
在序列化对象的所有属性之前执行某些操作
package com.alibaba.fastjson.serializer;public abstract class BeforeFilter implements SerializeFilter {private static final ThreadLocal<JSONSerializer> serializerLocal = new ThreadLocal<JSONSerializer>();private static final ThreadLocal<Character> seperatorLocal = new ThreadLocal<Character>();private final static Character COMMA = Character.valueOf(',');final char writeBefore(JSONSerializer serializer, Object object, char seperator) {serializerLocal.set(serializer);seperatorLocal.set(seperator);writeBefore(object);serializerLocal.set(null);return seperatorLocal.get();}protected final void writeKeyValue(String key, Object value) {JSONSerializer serializer = serializerLocal.get();char seperator = seperatorLocal.get();serializer.writeKeyValue(seperator, key, value);if (seperator != ',') {seperatorLocal.set(COMMA);}}//需要实现的方法,在实际实现中可以调用writeKeyValue增加json的内容public abstract void writeBefore(Object object);}
AfterFilter
在序列化对象的所有属性之后执行某些操作
package com.alibaba.fastjson.serializer;/*** @since 1.1.35*/public abstract class AfterFilter implements SerializeFilter {private static final ThreadLocal<JSONSerializer> serializerLocal = new ThreadLocal<JSONSerializer>();private static final ThreadLocal<Character> seperatorLocal = new ThreadLocal<Character>();private final static Character COMMA = Character.valueOf(',');final char writeAfter(JSONSerializer serializer, Object object, char seperator) {serializerLocal.set(serializer);seperatorLocal.set(seperator);writeAfter(object);serializerLocal.set(null);return seperatorLocal.get();}protected final void writeKeyValue(String key, Object value) {JSONSerializer serializer = serializerLocal.get();char seperator = seperatorLocal.get();serializer.writeKeyValue(seperator, key, value);if (seperator != ',') {seperatorLocal.set(COMMA);}}//子类需要实现的方法,实际使用的时候可以调用writeKeyValue增加内容public abstract void writeAfter(Object object);}
LabelFilter
根据 JsonField配置的label来判断是否进行输出
package com.alibaba.fastjson.serializer;//根据 JsonField配置的label来判断是否进行输出public interface LabelFilter extends SerializeFilter {boolean apply(String label);}
- 以上是SerializeFilter全局的过滤器:JSON.toJSONString方法的参数中可以配置处理所有类型的SerializeFilter。 还有如下过滤器
- 类级别过滤器:Class_Level_SerializeFilter · alibaba/fastjson Wiki · GitHub
- 属性过滤器:使用PropertyPreFilter过滤属性使用SimplePropertyPreFilter过滤属性 · alibaba/fastjson Wiki · GitHub
- 多余字段处理器:ParseProcess · alibaba/fastjson Wiki · GitHub
- ExtraProcessor 用于处理多余的字段
- ExtraTypeProvider 用于处理多余字段时提供类型信息
- 定制反序列化:在fastjson-1.2.9版本后提供了ExtraProcessable接口,用于定制对象的反序列化功能,可用于添加没有的字段ExtraProcessable · alibaba/fastjson Wiki · GitHub
- 标签过滤:JSONField(label),相当于分组LabelFilter · alibaba/fastjson Wiki · GitHub
- 自动识别嵌套对象子类型:FieldTypeResolver FieldTypeResolver · alibaba/fastjson Wiki · GitHub
参考文档
JSONField · alibaba/fastjson Wiki · GitHub
JSON最佳实践 | kimmking’s blog
fastjson SerializerFeature详解 - 孤天浪雨 - CSDN博客
fastjson详解 - 简书
