2021SC@SDUSC
简介
本篇主要分析SerializeFilter,首先做个大体的介绍,然后展示它的简单使用,最后简单分析它的源码
介绍
SerializeFilter可以定制我们转换json的场景,比如我们在转换某些对象为其JSON表示形式时,我们对于有些对象中的某些属性可能不想转换,或者当我们从数据库中拿出所有的条目时只有部分符合条件的对象应该转换为JSON对象并通过网络传输,若使用fastjson转换,这个时候就要用到SerializeFilter来定制我们的使用场景。
我们观察SerializeFilter的类图结构,发现SerializeFilter接口被多个接口继承,我们定制化的过程就是去实现这些接口的方法,我们看到继承SerializeFilter的接口有如下:
- PropertyPreFilter 根据PropertyName判断是否序列化
- PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
- NameFilter 修改Key,如果需要修改Key,process返回值则可
- ValueFilter 修改Value
其中BeforeFilter和AfterFilter不是接口而是抽象类分别时序列化时添加在之前和之后的类
使用
说明:
使用User类
public class User {
private String name;
private int age;
}
1.PropertyPreFilter
PropertyPreFilter propertyPreFilter = new PropertyPreFilter() {
@Override
public boolean apply(JSONSerializer jsonSerializer, Object o, String s) {
if("name".equals(s)){
String n = ((User)o).getName();
return n=="ck";
}
return false;
}
};
我们先定制化PropertyPreFilter的使用,重载apply方法,我们把只有name属性为ck的对象转换为json
测试代码:
User user = new User();
user.setName("chengkai");
user.setAge(20);
User user1 = new User();
user1.setName("ck");
user1.setAge(20);
System.out.println(JSON.toJSONString(user,propertyPreFilter));
System.out.println(JSON.toJSONString(user1,propertyPreFilter));
输出结果:
我们发现它是少输出了一个属性age,我们将重写apply的方法修改为:
public boolean apply(JSONSerializer jsonSerializer, Object o, String s) {
System.out.println("s="+s);
if("name".equals(s)){
String n = ((User)o).getName();
return n=="ck";
}
return false;
}
将参数s打印出来,
发现调用filter的过程是将对象的属性一个一个放进去的,若是我们想打印age参数就得将测试代码修改为:
public boolean apply(JSONSerializer jsonSerializer, Object o, String s) {
System.out.println("s="+s);
if("name".equals(s)){
String n = ((User)o).getName();
return n=="ck";
}else if("age".equals(s)){
return ((User)o).getAge() == 19;
}
return false;
}
此时的输出为如下
由此我们看出PropertyPreFilter的过滤效果只能去一个一个属性的过滤,若是我们将默认的return为true,将我们关注的属性判断返回为false,这样的结果也只是过滤属性,无法达到根据某个属性直接不转换整个对象的效果,但对于过滤对象的属性还是很有用的
2.PropertyFilter
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
*/
boolean apply(Object object, String name, Object value);
}
我们看到它传入的参数发生了变化,
第一个Object object是当前正在转换的对象
String name是正在检查属性的名称
Object value是该属性的具体值
PropertyFilter propertyFilter = new PropertyFilter() {
@Override
public boolean apply(Object o, String s, Object o1) {
if ("age".equals(s)){
int a = (int)o1;
return a == 20;
}
return false;
}
};
System.out.println(JSON.toJSONString(user,propertyFilter));
System.out.println(JSON.toJSONString(user1,propertyFilter));
输出:
本质上这个方法和PropertyPreFilter没什么区别,只是后面接收的参数多了一个当前属性的值。
3.NameFilter
先来看它的源码:
public interface NameFilter extends SerializeFilter {
String process(Object object, String name, Object value);
}
它的定制化方法返回的是一个String,这个String返回的是处理的属性的key,可以达到修改返回的json的key-value中的key的效果
测试:
NameFilter filter = new NameFilter() {
@Override
public String process(Object o, String s, Object o1) {
if ("name".equals(s)){
return "@"+ s;
}
return s;
}
};
System.out.println(JSON.toJSONString(user));
System.out.println(JSON.toJSONString(user,filter));
输出:
可以看大返回的name上多了个@;
4.ValueFilter
源码:
public interface NameFilter extends SerializeFilter {
String process(Object object, String name, Object value);
}
ValueFilter可以修改返回的json字符串中key-value中的value,示例:
ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object o, String s, Object o1) {
if ("name".equals(s)){
return "该同学的名字是最高机密";
}
return s;
}
};
System.out.println(JSON.toJSONString(user));
System.out.println(JSON.toJSONString(user,filter));
输出:
5.BeforeFilter
源码
public abstract class BeforeFilter implements SerializeFilter {
public abstract void writeBefore(Object object);
}
源码中有一些方法和变量,那不是我们定制关注的重点,所以我没有放进去,BeforeFilter可以在序列化前获取对象并执行一些我们定制化的操作
示例:
BeforeFilter filter = new BeforeFilter() {
@Override
public void writeBefore(Object o) {
User user = (User)o;
System.out.println(user.getName()+" "+ user.getAge());
user.setName("该同学的名字是个机密");
}
};
System.out.println(JSON.toJSONString(user)); System.out.println(JSON.toJSONString(user,filter));
输出:
其中的参数Object o即在序列化前获取到的完整对象,由于在java中获取的形式参数为非基本类型对象时,相当于获取了原对象的别名,所以我们在此处的调用了setName方法也会修改最终要输出的对象;
6.AfterFilter
源码:
public abstract class AfterFilter implements SerializeFilter {
public abstract void writeAfter(Object object);
}
该方法是在序列化后获取到对象,可以执行一些相关操作,由于对对象的操作是在序列化后才进行的,所以当前序列化的结果并不会发生变化:
测试代码:
AfterFilter filter = new AfterFilter() {
@Override
public void writeAfter(Object o) {
User user = (User)o;
System.out.println(user.getName()+" "+ user.getAge());
user.setName("该同学的名字是个机密");
}
};
System.out.println(JSON.toJSONString(user));
System.out.println(JSON.toJSONString(user,filter));
System.out.println(JSON.toJSONString(user));
输出:
可以看到,在调用该方法时输出了 chengkei 20,但是修改对象的方法却没有发挥作用,因为我们看到用了filter的序列化和初始没用的输出是一模一样的,但是最后一遍的输出确是序列化之后才执行,也就是说我们虽然在序列化前调用了该方法,但是对于对象的修改却是在序列化之后才完成的;
源码分析
我们来关注toJSONString这个方法是怎么去调用filter的:
public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
return out.toString();
} finally {
out.close();
}
}
这是toJSONString的源码,我们重点关注其中的代码:
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
它将filters参数通过addFilter方法加到JSONSerializer对象中,这个方法是JSONSerializer继承自父类SerializeFilterable的方法,它们有如下关系:
SerializeFilterable这个抽象类中维护着所有的filter:
protected List<BeforeFilter> beforeFilters = null;
protected List<AfterFilter> afterFilters = null;
protected List<PropertyFilter> propertyFilters = null;
protected List<ValueFilter> valueFilters = null;
protected List<NameFilter> nameFilters = null;
protected List<PropertyPreFilter> propertyPreFilters = null;
protected List<LabelFilter> labelFilters = null;
protected List<ContextValueFilter> contextValueFilters = null;
然后这些方法在
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
writer.write方法中被调用,因为我们使用的例子都是bean,所以我们查看JavaBeanSerializer,该类实现了接口ObjectSerializer,它的write方法中有:
if (!this.apply(serializer, object, fieldInfoName, propertyValue)) {
continue;
}
它通过这样的方式就调用了传入的filter