FastJSON 源码分析

Git 链接

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

git:https://github.com/alibaba/fastjson

Samples:https://github.com/alibaba/fastjson/wiki/Samples-DataBind

测试代码

@Test
public void test() {
    User user = new User(0L, "json");
    String jsonString = JSON.toJSONString(user);
    System.out.println(jsonString);
    User parseUser = JSON.parseObject(jsonString, User.class);
    System.out.println(parseUser);
}
public class User {
    private Long   id;
    private String name;
    
    public User(long id, String name) {
        this.id = id;
        this.name = name;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }
}

输出:

{"id":0,"name":"json"}
User [id=0, name=json]

序列化、反序列化流程

序列化流程

根据对象的实例,获取对象的类,判断出实现 ObjectSerializer 接口的类,调用接口的方法 write,将对象实例转化成 String。

反序列化流程

根据输入的 Class<T> clazz,判断出实现 ObjectDeserializer 的类,调用接口的方法 deserialze,将 String 转化成对象实例。

序列化源码分析

最终会调用到函数:

public static String toJSONString(Object object, // 
                                  SerializeConfig config, // 
                                  SerializeFilter[] filters, // 
                                  String dateFormat, //
                                  int defaultFeatures, // 
                                  SerializerFeature... features) {
    // out 对象保存解析对象的结果,最终会转换成 string(return out.toString();)
    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);
            }
        }
        // 将对象 object 解析成 string,保存在内部的 out 中
        serializer.write(object);
        return out.toString();
    } finally {
        out.close();
    }
}

其中 write 方法如下:

public final void write(Object object) {
    if (object == null) {
        out.writeNull();
        return;
    }
    Class<?> clazz = object.getClass();
    /**
     * 获取到对应的解析类,所有的类都实现了接口 ObjectSerializer
     * 
     * 如果是 bool,会定位到 BooleanCodec 类
     * 如果是 bool[],会定位到 PrimitiveArraySerializer 类
     */
    ObjectSerializer writer = getObjectWriter(clazz);
    try {
        // 调用 write 方法,把对应的域,写入 out 对象中!
        writer.write(this, object, null, null, 0);
    } catch (IOException e) {
        throw new JSONException(e.getMessage(), e);
    }
}

在测试用例中,使用的是类 JavaBeanSerializer,因为要序列化的是自定义的 JavaBean 类 User。

SerializeConfig

其中 put 函数是将键值对放入 IdentityHashMap<Type, ObjectSerializer> serializers 中。

public SerializeConfig(int tableSize, boolean fieldBase) {
    this.fieldBased = fieldBase;
    serializers = new IdentityHashMap<Type, ObjectSerializer>(tableSize);
    
    try {
        if (asm) {
            asmFactory = new ASMSerializerFactory();
        }
    } catch (Throwable eror) {
        asm = false;
    }
    put(Boolean.class, BooleanCodec.instance);
    put(Character.class, CharacterCodec.instance);
    put(Byte.class, IntegerCodec.instance);
    put(Short.class, IntegerCodec.instance);
    put(Integer.class, IntegerCodec.instance);
    put(Long.class, LongCodec.instance);
    put(Float.class, FloatCodec.instance);
    put(Double.class, DoubleSerializer.instance);
    put(BigDecimal.class, BigDecimalCodec.instance);
    put(BigInteger.class, BigIntegerCodec.instance);
    put(String.class, StringCodec.instance);
    put(byte[].class, PrimitiveArraySerializer.instance);
    put(short[].class, PrimitiveArraySerializer.instance);
    put(int[].class, PrimitiveArraySerializer.instance);
    put(long[].class, PrimitiveArraySerializer.instance);
    put(float[].class, PrimitiveArraySerializer.instance);
    put(double[].class, PrimitiveArraySerializer.instance);
    put(boolean[].class, PrimitiveArraySerializer.instance);
    put(char[].class, PrimitiveArraySerializer.instance);
    put(Object[].class, ObjectArrayCodec.instance);
    put(Class.class, MiscCodec.instance);
    // 省略……
    put(LinkedList.class, CollectionCodec.instance);
}

分析其中的代码:

put(Boolean.class, BooleanCodec.instance);

类 BooleanCodec 继承了接口 ObjectSerializer, ObjectDeserializer,两个接口:

public interface ObjectSerializer {
    
    /**
     * fastjson invokes this call-back method during serialization when it encounters a field of the
     * specified type.
     * @param serializer 
     * @param object src the object that needs to be converted to Json.
     * @param fieldName parent object field name
     * @param fieldType parent object field type
     * @param features parent object field serializer features
     * @throws IOException
     */
    void write(JSONSerializer serializer, //
               Object object, //
               Object fieldName, //
               Type fieldType, //
               int features) throws IOException;
}
public interface ObjectDeserializer {
    /**
     * fastjson invokes this call-back method during deserialization when it encounters a field of the
     * specified type.
     * <p>In the implementation of this call-back method, you should consider invoking
     * {@link JSON#parseObject(String, Type, Feature[])} method to create objects
     * for any non-trivial field of the returned object. 
     *
     * @param parser context DefaultJSONParser being deserialized
     * @param type The type of the Object to deserialize to
     * @param fieldName parent object field name
     * @return a deserialized object of the specified type which is a subclass of {@code T}
     */
    <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
    
    int getFastMatchToken();
}

BooleanCodec 的 write 实现如下,其中参数 serializer 中包含实例为 out 的 SerializeWriter 对象,out 最终转换成输出的 string;

public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
    SerializeWriter out = serializer.out;
    Boolean value = (Boolean) object;
    if (value == null) {
        out.writeNull(SerializerFeature.WriteNullBooleanAsFalse);
        return;
    }
    if (value.booleanValue()) {
        out.write("true");
    } else {
        out.write("false");
    }
}

BooleanCodec 的 deserialze 实现如下,如果 lexer.token() 是 true、1等,就会返回true;类 JSONToken 中有对各种字符的定义。

@SuppressWarnings("unchecked")
public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
    final JSONLexer lexer = parser.lexer;
    Boolean boolObj;
    try {
        if (lexer.token() == JSONToken.TRUE) {
            lexer.nextToken(JSONToken.COMMA);
            boolObj = Boolean.TRUE;
        } else if (lexer.token() == JSONToken.FALSE) {
            lexer.nextToken(JSONToken.COMMA);
            boolObj = Boolean.FALSE;
        } else if (lexer.token() == JSONToken.LITERAL_INT) {
            int intValue = lexer.intValue();
            lexer.nextToken(JSONToken.COMMA);
            if (intValue == 1) {
                boolObj = Boolean.TRUE;
            } else {
                boolObj = Boolean.FALSE;
            }
        } else {
            Object value = parser.parse();
            if (value == null) {
                return null;
            }
            boolObj = TypeUtils.castToBoolean(value);
        }
    } catch (Exception ex) {
        throw new JSONException("parseBoolean error, field : " + fieldName, ex);
    }
    if (clazz == AtomicBoolean.class) {
        return (T) new AtomicBoolean(boolObj.booleanValue());
    }
    return (T) boolObj;
}

反序列化

在反序列化string到对象时,会调用下面的函数。其中最重要的是第25行代码,将输入的input字符串转换成对应的class类型。

@SuppressWarnings("unchecked")
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor,
                                      int featureValues, Feature... features) {
    if (input == null) {
        return null;
    }
    if (features != null) {
        for (Feature feature : features) {
            featureValues |= feature.mask;
        }
    }
    DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);
    if (processor != null) {
        if (processor instanceof ExtraTypeProvider) {
            parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
        }
        if (processor instanceof ExtraProcessor) {
            parser.getExtraProcessors().add((ExtraProcessor) processor);
        }
        if (processor instanceof FieldTypeResolver) {
            parser.setFieldTypeResolver((FieldTypeResolver) processor);
        }
    }
    // 获取所需要的类
    T value = (T) parser.parseObject(clazz, null);
    parser.handleResovleTask(value);
    parser.close();
    return (T) value;
}

T value = (T) parser.parseObject(clazz, null) 的代码如下,对于本例中的 User 对象,最终ObjectDeserializer会定位到类JavaBeanDeserializer,其 deserialze 代码有点长,就不贴出来了。

@SuppressWarnings("unchecked")
public <T> T parseObject(Type type, Object fieldName) {
    int token = lexer.token();
    if (token == JSONToken.NULL) {
        lexer.nextToken();
        return null;
    }
    if (token == JSONToken.LITERAL_STRING) {
        if (type == byte[].class) {
            byte[] bytes = lexer.bytesValue();
            lexer.nextToken();
            return (T) bytes;
        }
        if (type == char[].class) {
            String strVal = lexer.stringVal();
            lexer.nextToken();
            return (T) strVal.toCharArray();
        }
    }
    // 根据输入的class类型,获取解析所需要的类
    ObjectDeserializer derializer = config.getDeserializer(type);
    try {
        return (T) derializer.deserialze(this, type, fieldName);
    } catch (JSONException e) {
        throw e;
    } catch (Throwable e) {
        throw new JSONException(e.getMessage(), e);
    }
}

其它用法

可以利用fastjson,将"1 2 3 4 5" 或 "1,2,3,4,5"这样的字符串,转换成数组。实际应用过程中,十分方便简洁。

@Test
public void testArray() {
    String arrayString = "1 2 3 4 5";
    int[] array1 = JSON.parseObject("[" + arrayString + "]", int[].class);
    System.out.println(Arrays.toString(array1));
    
    String boolString = "1, true, 0, false";
    boolean[] array2 = JSON.parseObject("[" + boolString + "]", boolean[].class);
    System.out.println(Arrays.toString(array2));
}

fastjson 的整理思路

总的来说,是定义了两个接口:ObjectSerializer 和 ObjectDeserializer 。针对不同的类,实现了不同的序列化和反序列化方式,并能够根据类的信息,选择合适的接口实现类。

总结

仅仅通过序列化、反序列化一个Java Bean对象,对fastjson的源码进行分析。很多地方没有展开讨论,至少没法通过博客的形式写出来,具体细节太多了。如果有什么问题,欢迎指正~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

一个 IT 青年北漂四年的感悟

工作这几年,每年都会有朋友离开北京,每次朋友跟我告别的时候总是让我有很多感慨,问自己什么时候回去。当初毕业来北京没想太多,只是出于对互联网的喜欢,而在老家又找不...

7820
来自专栏跟着阿笨一起玩NET

Image.FromFile 锁文件的解决办法

7310
来自专栏java一日一条

作为一个程序员我最大的遗憾

20多年前我处在了人生的一个十字路口。随着我们用5年时间为出版社(他们希望进入新兴的互联网空间)打造的Deltagraph的终结,我的第二家公司逐渐走向没落。那...

8310
来自专栏黄Java的地盘

《麦肯锡 问题分析与解决技巧》——阅读笔记(共16章)

《麦肯锡 问题分析与解决技巧》是一本关于问题分析与如何解决问题的书籍,在阅读过程中收获不少,因此留下读书笔记方便其他人来进行学习。

78710
来自专栏java一日一条

自由程序员的3个开发技巧

我们有三个系列的小技巧要分享:与你的客户沟通,保护你的声誉以及解决常见的自由职业问题。下面让我们开始吧!

8510
来自专栏跟着阿笨一起玩NET

YYYY-mm-dd HH:MM:SS

87320
来自专栏跟着阿笨一起玩NET

NULL不能和任何字段比较和运算

14210
来自专栏java一日一条

熬夜并不值得程序员炫耀

放弃睡眠就像是高利贷借款。没错,看上去你是得到了额外的时间,但你想得太乐观了,你知道代价是什么吗?放高利贷的会回来讨债,到时如果你不能支付的话,他就会夺走你的创...

7610
来自专栏跟着阿笨一起玩NET

不允许对64位应用程序进行修改”的解决方法

在64位系统中使用VS对程序(32位的)进行调试,出现“不允许对64位应用程序进行修改”的提示,如下图所示:

13010
来自专栏雪地二货笔记库

vue学习笔记9-监听属性-watch

这样就可以实现绑定 而且他后面也有很多功能,比如.lazy,惰性更新,只有焦点离开才会更新

9110

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励