谨慎修改fastjson的默认配置

fastjson提供了一个全局的修改序列化配置的方式。如果你对某个类型的默认序列化方式不满意,或者想指定自定义类型的序列化方式,那么你可以通过修改全局配置的方式实现。

修改序列化方式

修改已有类型的序列化方式

例如,你可以通过下面的方式修改 double 类型的序列化方式

1
2
SerializeConfig config = SerializeConfig.getGlobalInstance();
config.put(Double.class, new DoubleSerializer("#.##"));

这样,当你使用 JSON.toJSONString 序列化 double 类型的数据时,结果只会保留两位小数

1
2
3
4
5
// 代码
double cost = 16.232342143124d;
System.out.println(JSON.toJSONString(cost));

// 输出结果为 16.23,而不是 16.232342143124

指定自定义类型的序列化方式

另外一种情况是自定义类型,例如下面的类型

1
2
3
4
5
6
7
8
9
10
11
public static class Result {
public ResultCode code;
}

public static enum ResultCode {
LOGIN_FAILURE(8), INVALID_ARGUMENT(0), SIGN_ERROR(17);
public final int value;
ResultCode(int value){
this.value = value;
}
}

我们可以通过定义 ResultCode 对应的序列化方式,使得输出结果是 int 类型的 value 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义序列化方式
public static class ResultCodeSerilaizer implements ObjectSerializer {
public void write(JSONSerializer serializer,
Object object,
Object fieldName,
Type fieldType,
int features) throws IOException {
// 序列化时只保存value的值
serializer.write(((ResultCode) object).value);
}
}

// 注册到全局配置中
SerializeConfig.getGlobalInstance().put(ResultCode.class, new ResultCodeSerilaizer());

这样 JSON.toJSONString() 会使用 ResultCodeSerilaizer 序列化 ResultCode 类型

1
2
3
4
5
6
7
Result result = new Result();
result.code = ResultCode.SIGN_ERROR;

// 序列化的结果是 {"code":17}
String json = JSON.toJSONString(result);

Assert.assertEquals("{\"code\":17}", json);

一些建议

虽然通过上面的方式修改序列化方式很方便,但是在使用时还是要多加小心

不建议修改默认类型的序列化方式

修改默认类型的序列化方式,可能会产生一些意料之外的问题。例如,程序中可能已经存在很多使用 JSON.toJSONString 序列化的场景,指不定某些场景就依赖默认的序列化格式。在修改了默认类型的序列化方式后,有可能会导致这部分场景的逻辑不符合预期,更重要的是,通常情况下这种问题很难排查。我们最近就遇到了一次类似问题,花了好几个小时才定位到原因。因此,不建议修改默认类型的序列化方式。

如果是新增的自定义类型,只是用作内部使用,增加自定义的序列化方式倒不会有什么影响。但如果是要提供给外部使用,还是保持原样的好。

如何排查

如果真的遇到了序列化的问题,假如说怀疑是某个类型的序列化方式被修改了,那么可以通过 debug 的方式进行验证。在 debug 时,需要将断点打在修改的入口,即 SerializeConfigput 方法处,找到调用栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean put(Type type, ObjectSerializer value) {
// 将断点打在下面这行,最好选择条件断点,避免干扰
// 条件可设置为:type.equals(Double.class)
// 括号内输入你关注的类型
Type mixin = JSON.getMixInAnnotations(type);
if (mixin != null) {
IdentityHashMap<Type, ObjectSerializer> mixInClasses = this.mixInSerializers.get(type);
if (mixInClasses == null) {
//多线程下可能会重复创建,但不影响正确性
mixInClasses = new IdentityHashMap<Type, ObjectSerializer>(4);
mixInSerializers.put(type, mixInClasses);
}
return mixInClasses.put(mixin, value);
}
return this.serializers.put(type, value);
}