性能比较
这是我自己用jmh测试的记录
序列化
对象数量 | hutool | fastjson | jackson |
---|---|---|---|
100 | 0.17s | 0.17s | 0.52s |
1000 | 0.32s | 0.22s | 0.59s |
10000 | 1.73s | 0.61s | 0.68s |
100000 | 6.30s | 1.16s | 0.91s |
200000 | 10.95s | 1.76s | 1.26s |
反序列化
对象数量 | hutool | fastjson | jackson |
---|---|---|---|
100 | 0.18s | 0.29s | 0.57s |
1000 | 0.41s | 0.26s | 0.64s |
10000 | 1.84s | 0.46s | 0.68s |
100000 | 6.22s | 1.23s | 1.24s |
200000 | 12.83s | 2.57s | 1.83s |
可见数据量上去后,fastjson和jackson差距不大
迁移遇到的bug
默认情况下,fastjson会启用jsonpath来解决循环依赖。可以使用SerializerFeature.DisableCircularReferenceDetect来关闭此选项,但不推荐。但输出的带$ref的json不能直接用jackson读取。所以自己封装了一个Moudle:
import com.alibaba.fastjson.JSONPath;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.Objects;
/**
* @Date : 2022/7/30
* @Description : 兼容fastjson->jackson 迁移时$ref的path问题
*/
public class BeanRefMoudle extends Module {
@Override
public String getModuleName() {
return "beanRefMoudle";
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public void setupModule(SetupContext context) {
context.addBeanDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (deserializer instanceof BeanDeserializer) {
return new BeanRefDeserializer((BeanDeserializer) deserializer);
}
return deserializer;
}
});
}
}
@Slf4j
class BeanRefDeserializer extends BeanDeserializer {
private static final String REF="$ref";
public BeanRefDeserializer(BeanDeserializer src) {
super(src);
}
private static Object getSecondRootValue(JsonStreamContext pctx) {
if (Objects.isNull(pctx)) {
return null;
}
JsonStreamContext real;
do {
real = pctx;
pctx = pctx.getParent();
} while (!pctx.inRoot());
return real.getCurrentValue();
}
@Override
public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException {
if(Objects.equals(REF,p.getCurrentName())){
return match$ref(p);
}
return super.deserializeFromObject(p, ctxt);
}
private Object match$ref(JsonParser p) throws IOException {
p.nextToken();
try {
String ref=p.getValueAsString();
JsonStreamContext pctx = p.getParsingContext();
return JSONPath.eval(getSecondRootValue(pctx), ref);
} catch (Exception e) {
log.error("jackson解析{}异常",REF,e);
return null;
}finally {
p.nextToken();
}
}
}
再注册Moudle到SPI
resource文件夹下新建META-INF文件夹,META-INF文件夹下新建services文件夹,services文件夹下新建com.fasterxml.jackson.databind.Module文件,文件内容为你的模块全类名(com.xxx.xxxx.framework.json.BeanRefMoudle)