起因
今天项目中需要实现这么一个需求:要返回一个List<Map<>>,其中可能存在value为null的情况,这种情况需要保留null,返回结果为下面这种
[
{
"aaa": null,
"ccc": 2.0,
"ddd": "3"
},
{
"aaa": null,
"ccc": 2.0,
"ddd": "3"
},
{
"aaa": null,
"ccc": null,
"ddd": "4"
}
]
但是我们之前的其他接口的需求是如果为null就不返回,所以为了不影响其他接口,就需要单独来定义一个序列化实现。
探索
首先我就想到了用JSONField来指定序列化
@JSONField(serialzeFeatures = SerializerFeature.WriteMapNullValue)
private List<Map<String, Object>> list;
结果试了一下不行,推测是由于@JSONField并不是加在Map上的,导致不能生效,跟踪代码后发现,执行了这么一句
public final void writeWithFieldName(Object object, Object fieldName) {
writeWithFieldName(object, fieldName, null, 0);
}
public final void writeWithFieldName(Object object, Object fieldName, Type fieldType, int fieldFeatures) {
try {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
writer.write(this, object, fieldName, fieldType, fieldFeatures);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
这个fieldFeatures就是我们设置的序列化的参数,可以看到我们指定的参数在这里无论是什么都会被覆盖为0,所以我们在外面指定的格式就失效了
解决
既然用默认的序列化会失效,不如我们自己实现一个不会失效的序列化,我们可以将上面的代码复制过来,然后加以改动,最终代码就成了下面这样
@JSONField(serializeUsing = ListMapSerializer.class, serialzeFeatures = SerializerFeature.WriteMapNullValue)
private List<Map<String, Object>> list;
// 自定义序列化
public static class ListMapSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) {
// 如果为空,调用默认
if(object == null) {
serializer.write(object);
return;
}
// 不为空,调用features的序列化
Class<?> clazz = object.getClass();
ObjectSerializer writer = serializer.getObjectWriter(clazz);
try {
writer.write(serializer, object, null, null, features);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
}
这里在write的时候将传过来的features传进去,这样一来我们在上面指定的参数就能够正常使用了。
后记
对于fastjson的序列化,博主还不是很了解,所以对于内部代码的实现讲解的不是很详细,解决的方法可能也不是很优雅,欢迎大家指出问题,共同进步。