Android FastJson反序列化机制源码解析
一、FastJson反序列化基础概念
FastJson 是阿里巴巴开发的一款高效的 JSON 处理库,在 Android 开发中被广泛应用。反序列化是将 JSON 格式的字符串转换为 Java 对象的过程,这一过程是 FastJson 核心功能之一。理解反序列化机制,对于正确使用 FastJson、优化性能以及防范安全风险都有着重要意义。
FastJson 反序列化机制的核心目标是将 JSON 字符串按照一定规则映射为 Java 对象,其过程涉及到对 JSON 数据结构的解析、Java 类结构的识别以及属性值的正确赋值。在这个过程中,FastJson 运用了多种技术和策略,包括词法分析、语法分析、类型识别和属性绑定等。
二、FastJson核心类与基础结构
在深入解析反序列化机制之前,我们需要先了解 FastJson 中一些关键的类和基础结构,这些类和结构是反序列化过程的基石。
2.1 JSON类
JSON
类是 FastJson 的入口类,它提供了一系列静态方法用于 JSON 数据的序列化和反序列化操作。例如 parseObject
方法用于将 JSON 字符串解析为 Java 对象,parseArray
方法用于将 JSON 数组解析为 Java 集合等。
2.2 JSONReader类
JSONReader
类负责 JSON 数据的读取和解析。它基于字符流,逐字符读取 JSON 字符串,并根据 JSON 语法规则进行词法分析,将 JSON 字符串拆分为一个个 Token,如对象开始 {
、对象结束 }
、数组开始 [
、数组结束 ]
、字符串 "..."
、数字、布尔值 true
、false
、空值 null
等。
public class JSONReader {private String input;private int pos;public JSONReader(String input) {this.input = input;this.pos = 0;}// 读取下一个Tokenpublic Token nextToken() {skipWhitespace();char c = current();if (c == 0) {return Token.END;}// 省略其他Token判断逻辑if (c == '{') {pos++;return Token.BEGIN_OBJECT;}if (c == '}') {pos++;return Token.END_OBJECT;}// 其他Token判断...}// 跳过空白字符private void skipWhitespace() {while (true) {char c = current();if (c == 0 || c > 32) {break;}pos++;}}// 获取当前字符private char current() {if (pos >= input.length()) {return 0;}return input.charAt(pos);}
}
2.3 JSONParser类
JSONParser
类基于 JSONReader
进行更高层次的语法分析和反序列化操作。它将 JSONReader
读取的 Token 按照 JSON 语法规则组合成有意义的 JSON 结构,并根据目标 Java 类型将 JSON 数据转换为对应的 Java 对象。JSONParser
维护了一个解析上下文,用于存储解析过程中的各种状态信息,如当前解析的对象、属性名称等。
三、反序列化入口与基础流程
FastJson 反序列化的入口主要是 JSON
类的静态方法,如 parseObject
和 parseArray
。以 parseObject
方法为例,它有多个重载形式,最常用的是传入 JSON 字符串和目标 Java 类型的方法。
public static <T> T parseObject(String text, Type clazz) {JSONReader reader = new JSONReader(text);try {return (T) parseObject(reader, clazz, null, Feature.values());} finally {reader.close();}
}
上述代码首先创建了一个 JSONReader
实例用于读取 JSON 字符串,然后调用 parseObject
的重载方法进行实际的反序列化操作,并在最后关闭 JSONReader
。
在 parseObject
的重载方法中,会创建一个 JSONParser
实例,由 JSONParser
来执行具体的反序列化逻辑。
public static <T> T parseObject(JSONReader reader, Type clazz, Object fieldNameContext, Feature... features) {JSONParser parser = new JSONParser(reader, features);try {return (T) parser.parseObject(clazz, fieldNameContext);} finally {parser.close();}
}
JSONParser
的 parseObject
方法会根据传入的目标 Java 类型,判断是解析为普通 Java 对象、Java 集合还是其他复杂类型,然后进入相应的解析流程。如果是普通 Java 对象,会通过反射获取类的属性信息,并根据 JSON 数据中的属性名称和值,将值赋给对应的 Java 对象属性。
四、词法分析与Token识别
在反序列化的初始阶段,FastJson 需要对 JSON 字符串进行词法分析,将其拆分为一个个 Token,这一过程由 JSONReader
类完成。词法分析的准确性直接影响后续的语法分析和反序列化结果。
JSONReader
的 nextToken
方法是词法分析的核心方法。它会逐个字符读取 JSON 字符串,跳过空白字符,然后根据当前字符判断 Token 的类型。
public Token nextToken() {skipWhitespace();char c = current();if (c == 0) {return Token.END;}if (c == '{') {pos++;return Token.BEGIN_OBJECT;}if (c == '}') {pos++;return Token.END_OBJECT;}if (c == '[') {pos++;return Token.BEGIN_ARRAY;}if (c == ']') {pos++;return Token.END_ARRAY;}if (c == '"') {pos++;return Token.STRING;}if (c == '-' || (c >= '0' && c <= '9')) {return readNumber();}if (c == 't' || c == 'f') {return readBoolean();}if (c == 'n') {return readNull();}if (c == ',') {pos++;return Token.COMMA;}if (c == ':') {pos++;return Token.COLON;}throw new JSONException("syntax error");
}
对于字符串类型的 Token,JSONReader
会按照 JSON 字符串的规则进行读取,包括处理转义字符。
private Token readString() {StringBuilder sb = new StringBuilder();char c = current();pos++;while (true) {c = current();if (c == 0 || c == '"') {pos++;break;}if (c == '\\') {pos++;c = current();pos++;switch (c) {case 'b':sb.append('\b');break;case 't':sb.append('\t');break;case 'n':sb.append('\n');break;case 'f':sb.append('\f');break;case 'r':sb.append('\r');break;case '"':case '\\':case '/':sb.append(c);break;case 'u':sb.append(readUnicode());break;}} else {sb.append(c);pos++;}}setString(sb.toString());return Token.STRING;
}
通过词法分析,JSONReader
将 JSON 字符串转换为一系列有序的 Token,为后续的语法分析和反序列化提供了基础数据。
五、语法分析与结构构建
在完成词法分析后,JSONParser
基于 JSONReader
提供的 Token 进行语法分析,构建 JSON 数据的逻辑结构,并将其转换为对应的 Java 对象。
当遇到对象开始 Token BEGIN_OBJECT
时,JSONParser
会创建一个新的 Java 对象实例(通过反射),然后开始解析对象的属性。
public Object parseObject(Type clazz, Object fieldNameContext) {if (clazz == null) {return parse();}if (clazz == Object.class) {return parse();}if (clazz instanceof Class) {Class<?> rawClass = (Class<?>) clazz;if (rawClass.isArray()) {return parseArray(clazz, fieldNameContext);}if (Collection.class.isAssignableFrom(rawClass)) {return parseArray(clazz, fieldNameContext);}if (Map.class.isAssignableFrom(rawClass)) {return parseMap(clazz, fieldNameContext);}try {Object object = createJavaBean(clazz);parseObject(object, clazz, fieldNameContext);return object;} catch (Exception e) {throw new JSONException("create instance error", e);}}// 其他类型处理...return null;
}
在解析对象属性时,JSONParser
会读取属性名称(字符串类型的 Token),然后根据属性名称在 Java 类中查找对应的属性(通过反射获取类的所有属性)。找到属性后,继续读取属性值对应的 Token,并根据属性类型将 Token 转换为合适的 Java 值,最后将该值赋给 Java 对象的属性。
private void parseObject(Object object, Type clazz, Object fieldNameContext) {Class<?> rawClass = TypeUtils.getRawClass(clazz);Field[] fields = TypeUtils.compatibleWithJavaBean(rawClass) ? TypeUtils.getFields(rawClass) : TypeUtils.getDeclaredFields(rawClass);for (Field field : fields) {field.setAccessible(true);String fieldName = TypeUtils.getFieldName(field);if (!nextTokenWithColon(fieldName)) {continue;}Object value = parse();try {Type fieldType = field.getGenericType();Object realValue = TypeUtils.cast(value, fieldType, fieldNameContext);field.set(object, realValue);} catch (Exception e) {throw new JSONException("set property " + fieldName + " error", e);}}
}
当遇到数组开始 Token BEGIN_ARRAY
时,JSONParser
会创建一个 Java 集合(如 ArrayList
),然后逐个解析数组元素,并将元素添加到集合中。
public Object parseArray(Type clazz, Object fieldNameContext) {if (clazz == null) {return parseArray();}if (clazz instanceof Class) {Class<?> rawClass = (Class<?>) clazz;if (rawClass.isArray()) {return parseArray(rawClass, fieldNameContext);}}Collection<Object> list = createCollection(clazz);if (nextToken() != Token.BEGIN_ARRAY) {throw new JSONException("expect [, actual " + getTokenName());}for (;;) {if (nextToken() == Token.END_ARRAY) {break;}Object value = parse();list.add(value);if (nextToken() != Token.COMMA) {break;}}if (clazz instanceof Class && ((Class<?>) clazz).isArray()) {return toArray((Class<?>) clazz, list);}return list;
}
通过语法分析和结构构建,FastJson 成功地将 JSON 数据转换为对应的 Java 对象或集合,完成了反序列化的核心任务。
六、类型识别与转换
在反序列化过程中,准确识别 JSON 数据的类型并将其转换为对应的 Java 类型是至关重要的。FastJson 具备强大的类型识别和转换能力,能够处理多种数据类型,包括基本数据类型、包装类、字符串、集合、自定义对象等。
对于基本数据类型和包装类,FastJson 根据 JSON 数据的 Token 类型进行判断和转换。例如,当遇到数字类型的 Token 时,如果目标 Java 类型是 int
,则将数字字符串转换为 int
值;如果目标类型是 Integer
,则将其转换为 Integer
对象。
public static Object cast(Object value, Type type, Object fieldNameContext) {if (value == null) {return null;}if (type == null) {return value;}if (type == String.class) {return value.toString();}if (type == int.class || type == Integer.class) {if (value instanceof Number) {return ((Number) value).intValue();}return Integer.parseInt(value.toString());}// 其他类型转换逻辑...return value;
}
对于集合类型,如 List
和 Map
,FastJson 会根据 JSON 数组和对象的结构进行解析和转换。对于 List
,会将 JSON 数组中的每个元素按照对应位置转换为合适的 Java 类型,并添加到 List
中;对于 Map
,会将 JSON 对象的属性名称作为键,属性值转换为合适的 Java 类型后作为值,构建 Map
对象。
当处理自定义对象时,FastJson 通过反射获取类的属性信息,并根据 JSON 数据中的属性名称和值,将值转换为属性对应的 Java 类型。如果属性类型是另一个自定义对象,FastJson 会递归地进行反序列化,将 JSON 子对象转换为对应的子对象实例。
private Object createJavaBean(Type clazz) throws IllegalAccessException, InstantiationException {Class<?> rawClass = TypeUtils.getRawClass(clazz);if (rawClass.isInterface()) {throw new JSONException("can not create instance of " + clazz);}if (rawClass.isEnum()) {return null;}return rawClass.newInstance();
}
七、属性绑定与对象构建
属性绑定是将 JSON 数据中的属性值与 Java 对象的属性进行匹配和赋值的过程,这是反序列化的关键步骤之一。FastJson 通过反射机制实现属性绑定,确保 JSON 数据能够准确地填充到 Java 对象中。
在解析 JSON 对象时,JSONParser
会读取属性名称和属性值。对于每个属性名称,它会在 Java 类中查找对应的属性。查找过程首先会检查类的公共属性,然后检查通过 getter
和 setter
方法定义的属性(遵循 JavaBean 规范)。
private Field getField(Class<?> clazz, String name) {Field field = null;try {field = clazz.getField(name);} catch (NoSuchFieldException e) {try {field = clazz.getDeclaredField(name);} catch (NoSuchFieldException ex) {// 继续查找通过getter和setter定义的属性field = findPropertyField(clazz, name);}}return field;
}private Field findPropertyField(Class<?> clazz, String name) {// 查找getter方法Method getter = getGetterMethod(clazz, name);if (getter != null) {Type returnType = getter.getGenericReturnType();try {return clazz.getDeclaredField(name);} catch (NoSuchFieldException e) {// 没有对应字段,根据返回类型创建虚拟字段return createVirtualField(clazz, name, returnType);}}// 查找setter方法Method setter = getSetterMethod(clazz, name);if (setter != null) {Type[] parameterTypes = setter.getGenericParameterTypes();if (parameterTypes.length == 1) {try {return clazz.getDeclaredField(name);} catch (NoSuchFieldException e) {// 没有对应字段,根据参数类型创建虚拟字段return createVirtualField(clazz, name, parameterTypes[0]);}}}return null;
}
找到属性后,JSONParser
会将 JSON 数据中的属性值转换为属性对应的 Java 类型,并通过反射将值赋给属性。如果属性是私有的,会先调用 setAccessible(true)
来设置属性的可访问性。
private void setPropertyValue(Object object, Field field, Object value) {try {field.setAccessible(true);Type fieldType = field.getGenericType();Object realValue = TypeUtils.cast(value, fieldType, null);field.set(object, realValue);} catch (Exception e) {throw new JSONException("set property error", e);}
}
在属性绑定过程中,FastJson 还会处理一些特殊情况,如属性名称不匹配、属性类型转换失败等。对于属性名称不匹配的情况,可以通过 @JSONField
注解来指定 JSON 中的属性名称与 Java 类属性的对应关系;对于属性类型转换失败的情况,FastJson 会抛出异常