1. 对象和Json字符串之间的转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package example; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature;
public class doJson {
static String Object2Json(Object obj, SerializerFeature serializerFeature){ String jsonStr = JSON.toJSONString(obj, serializerFeature); return jsonStr; }
static Object Json2Object(String jsonStr){ Object o = JSON.parse(jsonStr); return o; }
public static void main(String[] args) { User user = new User(); String str = Object2Json(user, SerializerFeature.WriteNullNumberAsZero); System.out.println("User对象没有赋值转换为Json字符串:"); System.out.println(str); System.out.println(JSON.toJSONString(user)); user.setName("Lion"); user.setAge(18); user.setSchool("qinghua"); System.out.println("User对象字段赋值后转换为Json字符串:"); System.out.println(Object2Json(user, SerializerFeature.WriteNullNumberAsZero)); System.out.println("指定类后转换为Json字符串"); System.out.println(Object2Json(user, SerializerFeature.WriteClassName)); } }
|
2. 反序列化解析流程
这里主要看一下字符串转成Object的解析流程
2.1 创建JSON解析器
com.alibaba.fastjson.parse
- 创建默认的JSON解析器,默认的全局配置中有DenyList,1.2.24版本上只有两个Thread类
- 创建新的Json解析器中,跟入
new JSONScanner(intput, features)
- 进入
JSONScanner的构造方法,这里去了字符串的第一个字符,如{,判断了是否为\ufeff(Byte Order Mark,字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码)
- 进入
DefaultJSONParser构造方法
可以看到判断第一个字符是否为{如果是则取下一个字符,下面有个判断是否为[的,这个可以留着再分析 ,此时的token被指定为12
2.2 解析器工作
回到步骤1,进入parse.parse();首先判断Token是否正常,1,5,10,11,13,15,16,17,18,19都会抛出异常,这里感觉有很多的case分支,不知道的干什么的,也可以留下来
- 进入
com.alibaba.fastjson.parser.DefaultJSONParser#parseObject
第一步跳过空白字符,跟入方法看见 首先判断ch是否<='/',然后 、\r、\n、\t、\f、\b,如果等于/;循环判断是否为/、*、\n
如图会取Key值,即`""`中的字符,如`@type`
继续向下,判断Key是否为@type后,以"为单位获取对应的`Class`,ClassLoader为`this.config.getDefaultClassLoader`,此时为null
2.2.1 @type类加载
这里首先通过mapping去直接获取Class,如果不是这些开头的key,则继续运行
如代码分析,有几个判断条件,首先判断第一个字符是否为`[`,其次判断是否为`L`且结束为`;`
- 为
[时,通过loadClass加载[后的字符,并返回Array动态数组
L开头时,去中间字符串类名,再次调用loadClass进行加载
接下来判断ClassLoader是否为空
如果为空则取Thread.currentThread().getContextClassLoader();
如果取Class失败,直接通过Class.forName获取类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public static Class<?> loadClass(String className, ClassLoader classLoader) { if (className != null && className.length() != 0) { Class<?> clazz = (Class)mappings.get(className); if (clazz != null) { return clazz; } else if (className.charAt(0) == '[') { Class<?> componentType = loadClass(className.substring(1), classLoader); return Array.newInstance(componentType, 0).getClass(); } else if (className.startsWith("L") && className.endsWith(";")) { String newClassName = className.substring(1, className.length() - 1); return loadClass(newClassName, classLoader); } else { try { if (classLoader != null) { clazz = classLoader.loadClass(className); mappings.put(className, clazz); return clazz; } } catch (Throwable var6) { var6.printStackTrace(); }
try { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { clazz = contextClassLoader.loadClass(className); mappings.put(className, clazz); return clazz; } } catch (Throwable var5) { }
try { clazz = Class.forName(className); mappings.put(className, clazz); return clazz; } catch (Throwable var4) { return clazz; } } } else { return null; } }
|
2.2.2 类加载成功后
这里会执行nextToken,先看看nextToken是什么,如果token=13,则进入一段执行代码,通过查看nextToken中代码,发现ch=}时会导致token=13
这里先跳过他,如果是}的话,大概逻辑也就是实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| if (lexer.token() == 13) { lexer.nextToken(16);
try { instance = null; ObjectDeserializer deserializer = this.config.getDeserializer(clazz); if (deserializer instanceof JavaBeanDeserializer) { instance = ((JavaBeanDeserializer)deserializer).createInstance(this, clazz); }
if (instance == null) { if (clazz == Cloneable.class) { instance = new HashMap(); } else if ("java.util.Collections$EmptyMap".equals(ref)) { instance = Collections.emptyMap(); } else { instance = clazz.newInstance(); } }
obj = instance; return obj; } catch (Exception var23) { throw new JSONException("create instance error", var23); } }
|
1
| ObjectDeserializer deserializer = this.config.getDeserializer(clazz);
|
查看这个方法,判断type是否是Class类型、ParameterizedType类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| public ObjectDeserializer getDeserializer(Type type) { ObjectDeserializer derializer = (ObjectDeserializer)this.derializers.get(type); if (derializer != null) { return derializer; } else if (type instanceof Class) { return this.getDeserializer((Class)type, type); } else if (type instanceof ParameterizedType) { Type rawType = ((ParameterizedType)type).getRawType(); return rawType instanceof Class ? this.getDeserializer((Class)rawType, type) : this.getDeserializer(rawType); } else { return JavaObjectDeserializer.instance; } }
|
2.2.3 获取反序列化工具类
getDeserializer方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| public ObjectDeserializer getDeserializer(Class<?> clazz, Type type) { ObjectDeserializer derializer = (ObjectDeserializer)this.derializers.get(type); if (derializer != null) { return derializer; } else { if (type == null) { type = clazz; }
ObjectDeserializer derializer = (ObjectDeserializer)this.derializers.get(type); if (derializer != null) { return (ObjectDeserializer)derializer; } else { JSONType annotation = (JSONType)clazz.getAnnotation(JSONType.class); if (annotation != null) { Class<?> mappingTo = annotation.mappingTo(); if (mappingTo != Void.class) { return this.getDeserializer(mappingTo, mappingTo); } }
if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) { derializer = (ObjectDeserializer)this.derializers.get(clazz); }
if (derializer != null) { return (ObjectDeserializer)derializer; } else { String className = clazz.getName(); className = className.replace('$', '.');
for(int i = 0; i < this.denyList.length; ++i) { String deny = this.denyList[i]; if (className.startsWith(deny)) { throw new JSONException("parser deny : " + className); } }
if (className.startsWith("java.awt.") && AwtCodec.support(clazz) && !awtError) { try { this.derializers.put(Class.forName("java.awt.Point"), AwtCodec.instance); this.derializers.put(Class.forName("java.awt.Font"), AwtCodec.instance); this.derializers.put(Class.forName("java.awt.Rectangle"), AwtCodec.instance); this.derializers.put(Class.forName("java.awt.Color"), AwtCodec.instance); } catch (Throwable var11) { awtError = true; }
derializer = AwtCodec.instance; }
if (!jdk8Error) { try { if (className.startsWith("java.time.")) { this.derializers.put(Class.forName("java.time.LocalDateTime"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.LocalDate"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.LocalTime"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.ZonedDateTime"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.OffsetDateTime"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.OffsetTime"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.ZoneOffset"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.ZoneRegion"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.ZoneId"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.Period"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.Duration"), Jdk8DateCodec.instance); this.derializers.put(Class.forName("java.time.Instant"), Jdk8DateCodec.instance); derializer = (ObjectDeserializer)this.derializers.get(clazz); } else if (className.startsWith("java.util.Optional")) { this.derializers.put(Class.forName("java.util.Optional"), OptionalCodec.instance); this.derializers.put(Class.forName("java.util.OptionalDouble"), OptionalCodec.instance); this.derializers.put(Class.forName("java.util.OptionalInt"), OptionalCodec.instance); this.derializers.put(Class.forName("java.util.OptionalLong"), OptionalCodec.instance); derializer = (ObjectDeserializer)this.derializers.get(clazz); } } catch (Throwable var10) { jdk8Error = true; } }
if (className.equals("java.nio.file.Path")) { this.derializers.put(clazz, MiscCodec.instance); }
if (clazz == Entry.class) { this.derializers.put(clazz, MiscCodec.instance); }
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try { Iterator var17 = ServiceLoader.load(AutowiredObjectDeserializer.class, classLoader).iterator();
while(var17.hasNext()) { AutowiredObjectDeserializer autowired = (AutowiredObjectDeserializer)var17.next(); Iterator var8 = autowired.getAutowiredFor().iterator();
while(var8.hasNext()) { Type forType = (Type)var8.next(); this.derializers.put(forType, autowired); } } } catch (Exception var12) { }
if (derializer == null) { derializer = (ObjectDeserializer)this.derializers.get(type); }
if (derializer != null) { return (ObjectDeserializer)derializer; } else { if (clazz.isEnum()) { derializer = new EnumDeserializer(clazz); } else if (clazz.isArray()) { derializer = ObjectArrayCodec.instance; } else if (clazz != Set.class && clazz != HashSet.class && clazz != Collection.class && clazz != List.class && clazz != ArrayList.class) { if (Collection.class.isAssignableFrom(clazz)) { derializer = CollectionCodec.instance; } else if (Map.class.isAssignableFrom(clazz)) { derializer = MapDeserializer.instance; } else if (Throwable.class.isAssignableFrom(clazz)) { derializer = new ThrowableDeserializer(this, clazz); } else { derializer = this.createJavaBeanDeserializer(clazz, (Type)type); } } else { derializer = CollectionCodec.instance; }
this.putDeserializer((Type)type, (ObjectDeserializer)derializer); return (ObjectDeserializer)derializer; } } } } }
|
首先通过JSONType annotation = (JSONType)clazz.getAnnotation(JSONType.class);判断并获取类中注解
替换className中的$为.
2.2.3.1 类加载黑名单
判断是否为denyList,此时列表中只有两个线程类名
判断是否以java.awt.开头,java.awt.Point、 java.awt.Font 、java.awt.Rectangle 、java.awt.Color
- 放入指定的java.time.* 和java.util.Optional*
- 判断是否为
java.nio.file.Path
- 判断是否为
java.util.Entry
- 针对clazz做了一些类型的判断后,
derializer = this.createJavaBeanDeserializer(clazz, (Type)type);
createJavaBeanDeserializer
- 获取superClass,如果没有
superClass=clazz,判断类的方法修饰符是否为Public
- 判断clazz.getTypeParameters().length是否为0,如果底层泛型声明没有声明类型变量,则为0
ASMUtils.checkName(clazz.getSimpleName())检查类名
- 判断
clazz是否是接口
com.alibaba.fastjson.util.JavaBeanInfo.build创建beanInfo,其中初始化创建对象时,获取了clazz的Fields、Methods、Constructor
- 判断默认的构造方法是否为空,类不是接口,修饰符不是抽象的
- 判断
builderClass是否为空
- 遍历所有的
Method