序列化与反序列化是成对存在的,文中简称为序列化。
写在前面:
文中有很多源码,稍显凌乱。也主要是自己的一个记录,未字斟句酌。
简介 序列化(serialize) - 序列化是将对象转换为字节流。
反序列化(deserialize) - 反序列化是将字节流转换为对象。
序列化用途
将对象持久化,保存在内存、文件、数据库中
便于网络传输和传播
序列化工具 java序列化 - 性能比较普通
thrift 、protobuf - 适用于对性能敏感,对开发体验要求不高的内部系统。
hessian - 适用于对开发体验敏感,性能有要求的内外部系统。
jackson 、gson 、fastjson - 适用于对序列化后的数据要求有良好的可读性(转为 json 、xml 形式)。
Java序列化 实现Serializable或Externalizable接口。
前者有默认序列化逻辑,后者需要强制实现自己的序列化逻辑。底层实现都是Serializable。
本文主要关注Serializable。
使用 基础用法 实现Serializable接口,通过ObjectOutputStream来序列化,ObjectInputStream反序列化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Slf 4j@Data public class Person implements Serializable { private static final long serialVersionUID = 6666716291353949192L ; private Integer age; private String name; @Test public void test () throws IOException, ClassNotFoundException { Person person = new Person(); person.setAge(22 ); person.setName("lily" ); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("java.person.txt" )); objectOutputStream.writeObject(person); log.info("writeObject = {}" , person); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("java.person.txt" )); person = (Person) objectInputStream.readObject(); log.info("readObject = {}" , person); } }
输出
1 2 writeObject = Person(age=22, name=lily) readObject = Person(age=22, name=lily)
自定义用法 自定义序列化和反序列化逻辑,比如控制序列化字段、进行编码加密等。
在JavaBean中实现writeObject和readObject方法,方法签名是固定的。序列化过程中会判断JavaBean中的有无这样的方法,如果没有,就走入默认的defaultWriteFields和defaultReadFields的逻辑。
比如用age模拟加密和解密。
1 2 3 4 5 6 7 8 9 10 11 12 private void writeObject (ObjectOutputStream out) throws Exception { ObjectOutputStream.PutField putFields = out.putFields(); putFields.put("age" , age + 1 ); out.writeFields(); } private void readObject (ObjectInputStream in) throws Exception { ObjectInputStream.GetField readFields = in.readFields(); Integer encryptionAge = (Integer) readFields.get("age" , "" ); age = encryptionAge - 1 ; }
其他知识点
如果不实现Serializable接口,会抛出NotSerializableException异常。
如果属性是引用对象,引用对象也要实现序列化
一个子类实现Serializable 接口,父类也需要实现(否则父类信息不会被序列化)
静态字段不会参与序列化(序列化保存的是对象的状态,静态变量属于类的状态)
transient关键字修饰的对象不参与序列化
第二种自定义方式:writeReplace和readResolve
writeObject 序列化时会调用 writeReplace 方法将当前对象替换成另一个对象并将其写入流中,此时如果有自定义的 writeObject 也不会生效了
readResolve 会在 readObject 调用之后自动调用,它最主要的目的就是对反序列化的对象进行修改后返回
同一对象在一个ObjectOutputStream里writeObject多次,后面几次只会输出句柄信息
潜在问题: 如果在第一次序列化后,修改了内容,再次序列化时只会输出编码号,会丢失修改信息
serialVersionUID相当于类的版本号,如果没有显示定义serialVersionUID,编译期会根据类信息创建一个,当修改类后可能会引起反序列化失败(比如新增了字段,导致再次自动计算的serialVersionUID不相同)
serialVersionUID的idea快捷生成
实现原理 接口关系 引用这里 一张接口关系图
Serializable
和Externalizable
序列化接口
Serializable 接口没有方法或字段,仅用于标识可序列化的语义,实际上 ObjectOutputStream#writeObject 会判断JavaBean有没有自定义的writeObject 方法,如果没有则调用默认的序列化方法。
Externalizable 接口该接口中定义了两个扩展的抽象方法:writeExternal 与 readExternal。
DataOutput
和ObjectOutput
DataOutput 定义了对 8种Java 基本类型 byte、short、int、long、float、double、char、boolean,以及 String 的操作。
ObjectOutput 在 DataOutput 的基础上定义了对 Object 类型的操作。
ObjectOutputStream
一般使用 ObjectOutputStream#writeObject 方法把一个对象进行持久化。(ObjectInputStream#readObject 则从持久化存储中把对象读取出来。)
ObjectStreamClass
和 ObjectStreamField
ObjectStreamClass 是类的序列化描述符,包含类描述信息,字段的描述信息和 serialVersionUID。可以使用 lookup 方法找到创建在虚拟机中加载的具体类的 ObjectStreamClass。
ObjectStreamField 保存字段的序列化描述符,包括字段名、字段值等。
ObjectOutputStream源码分析 源码版本:jdk-12.0.1.jdk
ObjectOutputStream 数据结构 1 2 3 4 5 6 7 8 9 10 private final BlockDataOutputStream bout;private final HandleTable handles;private final ReplaceTable subs; private final boolean enableOverride;private boolean enableReplace;
ObjectOutputStream 构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public ObjectOutputStream (OutputStream out) throws IOException { verifySubclass(); bout = new BlockDataOutputStream(out); handles = new HandleTable(10 , (float ) 3.00 ); subs = new ReplaceTable(10 , (float ) 3.00 ); enableOverride = false ; writeStreamHeader(); bout.setBlockDataMode(true ); if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack(); } else { debugInfoStack = null ; } } protected void writeStreamHeader () throws IOException { bout.writeShort(STREAM_MAGIC); bout.writeShort(STREAM_VERSION); }
序列化入口 writeObject 引用这里 一张时序图
以下顺着基础用法的逻辑,看下代码实现。
1. writeObject 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public final void writeObject (Object obj) throws IOException { if (enableOverride) { writeObjectOverride(obj); return ; } try { writeObject0(obj, false ); } catch (IOException ex) { if (depth == 0 ) { writeFatalException(ex); } throw ex; } }
2. writeObject0 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 private void writeObject0 (Object obj, boolean unshared) throws IOException { boolean oldMode = bout.setBlockDataMode(false ); depth++; try { int h; if ((obj = subs.lookup(obj)) == null ) { writeNull(); return ; } else if (!unshared && (h = handles.lookup(obj)) != -1 ) { writeHandle(h); return ; } else if (obj instanceof Class) { writeClass((Class) obj, unshared); return ; } else if (obj instanceof ObjectStreamClass) { writeClassDesc((ObjectStreamClass) obj, unshared); return ; } Object orig = obj; Class<?> cl = obj.getClass(); ObjectStreamClass desc; for (;;) { Class<?> repCl; desc = ObjectStreamClass.lookup(cl, true ); if (!desc.hasWriteReplaceMethod() || (obj = desc.invokeWriteReplace(obj)) == null || (repCl = obj.getClass()) == cl) { break ; } cl = repCl; } if (enableReplace) { Object rep = replaceObject(obj); if (rep != obj && rep != null ) { cl = rep.getClass(); desc = ObjectStreamClass.lookup(cl, true ); } obj = rep; } if (obj != orig) { subs.assign(orig, obj); if (obj == null ) { writeNull(); return ; } else if (!unshared && (h = handles.lookup(obj)) != -1 ) { writeHandle(h); return ; } else if (obj instanceof Class) { writeClass((Class) obj, unshared); return ; } else if (obj instanceof ObjectStreamClass) { writeClassDesc((ObjectStreamClass) obj, unshared); return ; } } if (obj instanceof String) { writeString((String) obj, unshared); } else if (cl.isArray()) { writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { writeEnum((Enum<?>) obj, desc, unshared); } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } } } finally { depth--; bout.setBlockDataMode(oldMode); } }
2.1 writeString&writeArray&writeEnum 字符串、枚举的在这里就写值了
数组元素如果是原生类型的,也写值了,如果非原生,递归调用writeObject0
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 private void writeString (String str, boolean unshared) throws IOException { handles.assign(unshared ? null : str); long utflen = bout.getUTFLength(str); if (utflen <= 0xFFFF ) { bout.writeByte(TC_STRING); bout.writeUTF(str, utflen); } else { bout.writeByte(TC_LONGSTRING); bout.writeLongUTF(str, utflen); } } private void writeArray (Object array, ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_ARRAY); writeClassDesc(desc, false ); handles.assign(unshared ? null : array); Class<?> ccl = desc.forClass().getComponentType(); if (ccl.isPrimitive()) { if (ccl == Integer.TYPE) { int [] ia = (int []) array; bout.writeInt(ia.length); bout.writeInts(ia, 0 , ia.length); } else { throw new InternalError(); } } else { Object[] objs = (Object[]) array; int len = objs.length; bout.writeInt(len); if (extendedDebugInfo) { debugInfoStack.push( "array (class \"" + array.getClass().getName() + "\", size: " + len + ")" ); } try { for (int i = 0 ; i < len; i++) { if (extendedDebugInfo) { debugInfoStack.push( "element of array (index: " + i + ")" ); } try { writeObject0(objs[i], false ); } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } } } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } } } private void writeEnum (Enum<?> en, ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_ENUM); ObjectStreamClass sdesc = desc.getSuperDesc(); writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false ); handles.assign(unshared ? null : en); writeString(en.name(), false ); }
2.2 writeOrdinaryObject 普通JavaBean的序列化逻辑
写类型
写类信息
写类数据
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 private void writeOrdinaryObject (Object obj, ObjectStreamClass desc, boolean unshared) throws IOException { if (extendedDebugInfo) { debugInfoStack.push( (depth == 1 ? "root " : "" ) + "object (class \"" + obj.getClass().getName() + "\", " + obj.toString() + ")" ); } try { desc.checkSerialize(); bout.writeByte(TC_OBJECT); writeClassDesc(desc, false ); handles.assign(unshared ? null : obj); if (desc.isExternalizable() && !desc.isProxy()) { writeExternalData((Externalizable) obj); } else { writeSerialData(obj, desc); } } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } }
2.2.1 writeClassDesc 写类信息。
非代理类型的类信息,一般有类标志位、类名称、序列化协议版本、SUID、方法标志位、字段个数、然后每个字段的:字段TypeCode、字段名称、(非原生类型的)字段类型
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 private void writeClassDesc (ObjectStreamClass desc, boolean unshared) throws IOException { int handle; if (desc == null ) { writeNull(); } else if (!unshared && (handle = handles.lookup(desc)) != -1 ) { writeHandle(handle); } else if (desc.isProxy()) { writeProxyDesc(desc, unshared); } else { writeNonProxyDesc(desc, unshared); } } private void writeNonProxyDesc (ObjectStreamClass desc, boolean unshared) throws IOException { bout.writeByte(TC_CLASSDESC); handles.assign(unshared ? null : desc); if (protocol == PROTOCOL_VERSION_1) { desc.writeNonProxy(this ); } else { writeClassDescriptor(desc); } Class<?> cl = desc.forClass(); bout.setBlockDataMode(true ); if (cl != null && isCustomSubclass()) { ReflectUtil.checkPackageAccess(cl); } annotateClass(cl); bout.setBlockDataMode(false ); bout.writeByte(TC_ENDBLOCKDATA); writeClassDesc(desc.getSuperDesc(), false ); } void writeNonProxy (ObjectOutputStream out) throws IOException { out.writeUTF(name); out.writeLong(getSerialVersionUID()); byte flags = 0 ; if (externalizable) { flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; int protocol = out.getProtocolVersion(); if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { flags |= ObjectStreamConstants.SC_BLOCK_DATA; } } else if (serializable) { flags |= ObjectStreamConstants.SC_SERIALIZABLE; } if (hasWriteObjectData) { flags |= ObjectStreamConstants.SC_WRITE_METHOD; } if (isEnum) { flags |= ObjectStreamConstants.SC_ENUM; } out.writeByte(flags); out.writeShort(fields.length); for (int i = 0 ; i < fields.length; i++) { ObjectStreamField f = fields[i]; out.writeByte(f.getTypeCode()); out.writeUTF(f.getName()); if (!f.isPrimitive()) { out.writeTypeString(f.getTypeString()); } } }
2.2.2 writeSerailData 写类数据
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 private void writeSerialData (Object obj, ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); for (int i = 0 ; i < slots.length; i++) { ObjectStreamClass slotDesc = slots[i].desc; if (slotDesc.hasWriteObjectMethod()) { PutFieldImpl oldPut = curPut; curPut = null ; SerialCallbackContext oldContext = curContext; if (extendedDebugInfo) { debugInfoStack.push( "custom writeObject data (class \"" + slotDesc.getName() + "\")" ); } try { curContext = new SerialCallbackContext(obj, slotDesc); bout.setBlockDataMode(true ); slotDesc.invokeWriteObject(obj, this ); bout.setBlockDataMode(false ); bout.writeByte(TC_ENDBLOCKDATA); } finally { curContext.setUsed(); curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; } else { defaultWriteFields(obj, slotDesc); } } }
2.2.2.1 defaultWriteFields 真正写类数据的地方
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 private void defaultWriteFields (Object obj, ObjectStreamClass desc) throws IOException { Class<?> cl = desc.forClass(); if (cl != null && obj != null && !cl.isInstance(obj)) { throw new ClassCastException(); } desc.checkDefaultSerialize(); int primDataSize = desc.getPrimDataSize(); if (primDataSize > 0 ) { if (primVals == null || primVals.length < primDataSize) { primVals = new byte [primDataSize]; } desc.getPrimFieldValues(obj, primVals); bout.write(primVals, 0 , primDataSize, false ); } int numObjFields = desc.getNumObjFields(); if (numObjFields > 0 ) { ObjectStreamField[] fields = desc.getFields(false ); Object[] objVals = new Object[numObjFields]; int numPrimFields = fields.length - objVals.length; desc.getObjFieldValues(obj, objVals); for (int i = 0 ; i < objVals.length; i++) { if (extendedDebugInfo) { debugInfoStack.push( "field (class \"" + desc.getName() + "\", name: \"" + fields[numPrimFields + i].getName() + "\", type: \"" + fields[numPrimFields + i].getType() + "\")" ); } try { writeObject0(objVals[i], fields[numPrimFields + i].isUnshared()); } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } } } }
到这序列化的主体逻辑就结束了。
反序列化的主要操作和序列化都是一一对应的。读出每个类标志,用对应方式去解析。
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 private Object readObject0 (boolean unshared) throws IOException { boolean oldMode = bin.getBlockDataMode(); if (oldMode) { int remain = bin.currentBlockRemaining(); if (remain > 0 ) { throw new OptionalDataException(remain); } else if (defaultDataEnd) { throw new OptionalDataException(true ); } bin.setBlockDataMode(false ); } byte tc; while ((tc = bin.peekByte()) == TC_RESET) { bin.readByte(); handleReset(); } depth++; totalObjectRefs++; try { switch (tc) { case TC_NULL: return readNull(); case TC_REFERENCE: return readHandle(unshared); case TC_CLASS: return readClass(unshared); case TC_CLASSDESC: case TC_PROXYCLASSDESC: return readClassDesc(unshared); case TC_STRING: case TC_LONGSTRING: return checkResolve(readString(unshared)); case TC_ARRAY: return checkResolve(readArray(unshared)); case TC_ENUM: return checkResolve(readEnum(unshared)); case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION: IOException ex = readFatalException(); throw new WriteAbortedException("writing aborted" , ex); case TC_BLOCKDATA: case TC_BLOCKDATALONG: if (oldMode) { bin.setBlockDataMode(true ); bin.peek(); throw new OptionalDataException( bin.currentBlockRemaining()); } else { throw new StreamCorruptedException( "unexpected block data" ); } case TC_ENDBLOCKDATA: if (oldMode) { throw new OptionalDataException(true ); } else { throw new StreamCorruptedException( "unexpected end of block data" ); } default : throw new StreamCorruptedException( String.format("invalid type code: %02X" , tc)); } } finally { depth--; bin.setBlockDataMode(oldMode); } }
其他知识点 字段值的读取和写入 ObjectOutputStream写值的逻辑:获取到当前对象中的原生类型字段,primDataSize是对象中所有原生类型字段的总长度,desc.getPrimFieldValues(obj, primVals);
是将对象中的所有原生字段的值写入primVals这个字节数组,获取对象的值时是用Unsafe类直接通过偏移量取值,unsafe.getBoolean(obj, offset)
这样的方式。
同理,ObjectInputStream读值的逻辑,unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
实现在ObjectStreamClass#getPrimFieldValues
和ObjectStreamClass#setPrimFieldValues
共享句柄 序列化过程中出现过的对象、字符串、数值,甚至拼接出来的类信息,如果是shared模式,都不会再完整序列化一次,只会输出handles句柄的索引。
写入句柄的地方
一个直观的例子 举上面Person的例子。
write Person: person -> write Integer: age & write String: name
write Integer: age -> write int value(11) & write Number : null
write String: name
Person里再加Birthday one, Birthday two属性。
Birthday属性 year, month, day.
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 @Slf 4j@Data public class Person implements Serializable { private static final long serialVersionUID = 6666716291353949192L ; private Integer age; private String name; private Birthday one; private Birthday two; @Data class Birthday implements Serializable { private Integer year; private Integer month; private Integer day; } @Test public void test () throws IOException, ClassNotFoundException { Person person = new Person(); person.setAge(22 ); person.setName("lily" ); Birthday one = new Birthday(); one.setYear(2020 ); Birthday two = new Birthday(); two.setYear(2019 ); person.setOne(one); person.setTwo(two); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("java.person.txt" )); objectOutputStream.writeObject(person); log.info("writeObject = {}" , person); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("java.person.txt" )); person = (Person) objectInputStream.readObject(); log.info("readObject = {}" , person); } }
以JavaBean为例,不严谨的一份序列化结果接近这样:
魔数、版本号只在初始化写一次
魔数、版本号 | 类标志、类信息开始、类名称、序列化协议版本、SUID、一些序列信息标志(比如是Serializable还是externalizable..)、字段个数、(for每个字段的)字段TypeCode、字段名称、(非原生类型的)字段类型、类信息结束(向上递归父类的信息)【父类的类标志….(非原生类型的)字段类型、类信息结束】(从父类到子类,for每个类)所有原生字段的值+递归所有非原生字段的序列化
高亮那一段解释不来…可以解释了,Birthday的fields如debug截图
Gson JSON (JavaScript Object Notation)是一种轻量级数据交换格式。
使用 依赖 maven
1 2 3 4 5 6 <dependency > <groupId > com.google.code.gson</groupId > <artifactId > gson</artifactId > <version > 2.8.6</version > <scope > compile</scope > </dependency >
基础用法 api非常的简单、易用
基本类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Gson gson = new Gson(); gson.toJson(1 ); gson.toJson("abcd" ); gson.toJson(new Long(10 )); int [] values = { 1 };gson.toJson(values); int one = gson.fromJson("1" , int .class);Integer one = gson.fromJson("1" , Integer.class); Long one = gson.fromJson("1" , Long.class); Boolean false = gson.fromJson("false" , Boolean.class); String str = gson.fromJson("\"abc\"" , String.class); String[] anotherStr = gson.fromJson("[\"abc\"]" , String[].class);
引用类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class BagOfPrimitives { private int value1 = 1 ; private String value2 = "abc" ; private transient int value3 = 3 ; BagOfPrimitives() { } } BagOfPrimitives obj = new BagOfPrimitives(); Gson gson = new Gson(); String json = gson.toJson(obj); BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
数组 1 2 3 4 5 6 7 8 9 10 11 Gson gson = new Gson(); int [] ints = {1 , 2 , 3 , 4 , 5 };String[] strings = {"abc" , "def" , "ghi" }; gson.toJson(ints); gson.toJson(strings); int [] ints2 = gson.fromJson("[1,2,3,4,5]" , int [].class);
泛型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Foo <T > { T value; } Gson gson = new Gson(); Foo<Bar> foo = new Foo<Bar>(); gson.toJson(foo); gson.fromJson(json, foo.getClass()); Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType);
实现原理 核心:TypeAdapter 类型适配器,用到了适配器模式,作为JsonWriter/JsonReader和类型T的对象之间的适配器,将一个对象写入json数据,或从json数据中读入一个对象。
1 2 3 4 5 6 7 8 public abstract class TypeAdapter <T > { public abstract void write (JsonWriter out, T value) throws IOException ; public abstract T read (JsonReader in) throws IOException ; ... }
Gson为每一种类型创建一个TypeAdapter,同样的,每一个Type都对应唯一一个TypeAdapter。
在Gson中,类型Type大致可以分为两类:
基本平台类型,如int.class、Integer.class、String.class、Url.class等
组合及自定义类型,如Collection.class、Map.class和用户自定义的JavaBean等
引用这里 一张示意图:
Gson根据传入的Type找对应的TypeAdapter,如果是基本平台类型,利用TypeAdapter可直接读写json,如果是组合及自定义类型,则在对应的TypeAdapter里封装了对内部属性的处理,是一个迭代的过程(和上面Java自带的序列化writeOrdinaryObject&readOrdinaryObject是很类似的)。
源码分析 Gson属性和构造函数 一些属性
1 2 3 4 5 6 7 8 9 private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls = new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>(); private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>(); final List<TypeAdapterFactory> factories;
最终调用的构造函数
new Gson()
得到默认的实例,或者用GsonBuilder
自定义一些策略
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 Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy, Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle, int timeStyle, List<TypeAdapterFactory> builderFactories, List<TypeAdapterFactory> builderHierarchyFactories, List<TypeAdapterFactory> factoriesToBeAdded) { this .excluder = excluder; this .fieldNamingStrategy = fieldNamingStrategy; this .instanceCreators = instanceCreators; this .constructorConstructor = new ConstructorConstructor(instanceCreators); this .serializeNulls = serializeNulls; this .complexMapKeySerialization = complexMapKeySerialization; this .generateNonExecutableJson = generateNonExecutableGson; this .htmlSafe = htmlSafe; this .prettyPrinting = prettyPrinting; this .lenient = lenient; this .serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues; this .longSerializationPolicy = longSerializationPolicy; this .datePattern = datePattern; this .dateStyle = dateStyle; this .timeStyle = timeStyle; this .builderFactories = builderFactories; this .builderHierarchyFactories = builderHierarchyFactories; List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>(); factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); factories.add(ObjectTypeAdapter.FACTORY); factories.add(excluder); factories.addAll(factoriesToBeAdded); factories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.INTEGER_FACTORY); factories.add(TypeAdapters.BOOLEAN_FACTORY); factories.add(TypeAdapters.BYTE_FACTORY); factories.add(TypeAdapters.SHORT_FACTORY); TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy); factories.add(TypeAdapters.newFactory(long .class, Long.class, longAdapter)); factories.add(TypeAdapters.newFactory(double .class, Double.class, doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.newFactory(float .class, Float.class, floatAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.NUMBER_FACTORY); factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY); factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY); factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter))); factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter))); factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY); factories.add(TypeAdapters.CHARACTER_FACTORY); factories.add(TypeAdapters.STRING_BUILDER_FACTORY); factories.add(TypeAdapters.STRING_BUFFER_FACTORY); factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL)); factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER)); factories.add(TypeAdapters.URL_FACTORY); factories.add(TypeAdapters.URI_FACTORY); factories.add(TypeAdapters.UUID_FACTORY); factories.add(TypeAdapters.CURRENCY_FACTORY); factories.add(TypeAdapters.LOCALE_FACTORY); factories.add(TypeAdapters.INET_ADDRESS_FACTORY); factories.add(TypeAdapters.BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(TypeAdapters.CALENDAR_FACTORY); factories.add(TimeTypeAdapter.FACTORY); factories.add(SqlDateTypeAdapter.FACTORY); factories.add(TypeAdapters.TIMESTAMP_FACTORY); factories.add(ArrayTypeAdapter.FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); factories.add(new CollectionTypeAdapterFactory(constructorConstructor)); factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); this .jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); factories.add(jsonAdapterFactory); factories.add(TypeAdapters.ENUM_FACTORY); factories.add(new ReflectiveTypeAdapterFactory( constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory)); this .factories = Collections.unmodifiableList(factories); }
toJson 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Slf 4jpublic class LearningGsonTest { @Test public void testGson () { Person person = new Person(); person.setAge(22 ); person.setName("lily" ); log.info("person = {}" , person); Gson gson = new Gson(); String json = gson.toJson(person); log.info("json = {}" , json); person = gson.fromJson(json, Person.class); log.info("person = {}" , person); } }
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 public String toJson (Object src) { if (src == null ) { return toJson(JsonNull.INSTANCE); } return toJson(src, src.getClass()); } public String toJson (Object src, Type typeOfSrc) { StringWriter writer = new StringWriter(); toJson(src, typeOfSrc, writer); return writer.toString(); } public void toJson (Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); toJson(src, typeOfSrc, jsonWriter); } catch (IOException e) { throw new JsonIOException(e); } } public void toJson (Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc)); boolean oldLenient = writer.isLenient(); writer.setLenient(true ); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(serializeNulls); try { ((TypeAdapter<Object>) adapter).write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } catch (AssertionError e) { AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage()); error.initCause(e); throw error; } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } }
看一下TypeToken.get(typeOfSrc)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static TypeToken<?> get(Type type) { return new TypeToken<Object>(type); } @SuppressWarnings ("unchecked" )TypeToken(Type type) { this .type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type)); this .rawType = (Class<? super T>) $Gson$Types.getRawType(this .type); this .hashCode = this .type.hashCode(); }
穿插一下Java类型(Type)系统的介绍。
详细内容可以看这两篇文章Java中的Type类型详解](https://juejin.im/post/5adefaba518825670e5cb44d)和[Java Type类型](https://www.jianshu.com/p/39cc237ad815),或者Google下。
简单说明下
Type是Java语言中所有类型的公共父接口,有4个扩展接口,主要是用来记录泛型的信息(一个泛型中的信息可能是另一个泛型)
GenericArrayType:泛型数组类型,比如T[] array
、List<String>[] array
中的T[]
、List<String>[]
ParameterizedType:参数化类型,比如Lis<String> list
、Map<String,Object> map
中的Lis<String>
、Map<String,Object>
TypeVariable:类型变量,比如List<T> list
中的T
、Map<K,V> map
、E[] array
中的K
、V
、E
(一般外层还有一个GenericArrayType或者ParameterizedType)
WildcardType:通配符类型,比如Map<? extends A,? super B> map
中的? extends A
、? super B
,A
称为上界,B
称为下界;如果只有List<?> list
,默认下界是String,默认上界是Object
Class是Type的一个直接实现类
其他4个接口都有自己的实现类,在sun.reflect包下
举例子:
比如List<T extends Map>[] array
是一个泛型数组类型GenericArrayType,其中List<T>
是ParameterizedType,T
是TypeVariable
genericComponentType可以理解为数组中每个元素的(泛型)类型
再如List<? extends Map> list
,本身是一个ParameterizedType,? extends Map
是WildcardType
T[] array
,本身是GenericArrayType,T
是TypeVariable
getAdapter 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 @SuppressWarnings ("unchecked" )public <T> TypeAdapter<T> getAdapter (TypeToken<T> type) { TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); if (cached != null ) { return (TypeAdapter<T>) cached; } Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get(); boolean requiresThreadLocalCleanup = false ; if (threadCalls == null ) { threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>(); calls.set(threadCalls); requiresThreadLocalCleanup = true ; } FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type); if (ongoingCall != null ) { return ongoingCall; } try { FutureTypeAdapter<T> call = new FutureTypeAdapter<T>(); threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) { TypeAdapter<T> candidate = factory.create(this , type); if (candidate != null ) { call.setDelegate(candidate); typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type); } finally { threadCalls.remove(type); if (requiresThreadLocalCleanup) { calls.remove(); } } }
为什么要有个FutureTypeAdapter的本地缓存呢?
先剧透ReflectiveTypeAdapterFactory在创建adapter的时候,会遍历属性取对应的adapte。比如Person里有个Person属性,就会递归取Person的adapter..
1 2 3 4 5 6 7 @Data @Slf 4jpublic class Person { private Integer age; private String name; private Person person; }
FutureTypeAdapter本质上是个委托者,内部引用了真正的adapter,在执行json读写时会用这个真正的adapter进行操作。
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 static class FutureTypeAdapter <T > extends TypeAdapter <T > { private TypeAdapter<T> delegate; public void setDelegate (TypeAdapter<T> typeAdapter) { if (delegate != null ) { throw new AssertionError(); } delegate = typeAdapter; } @Override public T read (JsonReader in) throws IOException { if (delegate == null ) { throw new IllegalStateException(); } return delegate.read(in); } @Override public void write (JsonWriter out, T value) throws IOException { if (delegate == null ) { throw new IllegalStateException(); } delegate.write(out, value); } }
AdapterFactory 平台基础类型的Adapter是预先定义好的,每个类型对应一个adapter,比如String类型的AdapterFactory返回的adapter永远是TypeAdapters.STRING
复合类型和自定义类型(反射类型)的Adapter是需要动态创建的,因为泛型不同、JavaBean的属性不同,等等
接下来看3个实现,其他类型大同小异,理解的思路是一样的
String类型 STRING_FACTORY和’STRING_ADAPTER’
实际上没有STRING_ADAPTER这个名字,真正名字是STRING
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 public interface TypeAdapterFactory { <T> TypeAdapter<T> create (Gson gson, TypeToken<T> type) ; } public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING); public static <TT> TypeAdapterFactory newFactory ( final Class<TT> type, final TypeAdapter<TT> typeAdapter) { return new TypeAdapterFactory() { @SuppressWarnings ("unchecked" ) @Override public <T> TypeAdapter<T> create (Gson gson, TypeToken<T> typeToken) { return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null ; } @Override public String toString () { return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]" ; } }; } public static final TypeAdapter<String> STRING = new TypeAdapter<String>() { @Override public String read (JsonReader in) throws IOException { JsonToken peek = in.peek(); if (peek == JsonToken.NULL) { in.nextNull(); return null ; } if (peek == JsonToken.BOOLEAN) { return Boolean.toString(in.nextBoolean()); } return in.nextString(); } @Override public void write (JsonWriter out, String value) throws IOException { out.value(value); } };
Integer、Long、Boolean、AtomicInteger等等平台基础类型的factory的框架是类似的,或者一样的,有细微的差别(比如同时支持非包装类型和包装类型)
集合类型 CollectionTypeAdapterFactory
集合类型的factory和adapter
MapTypeAdapterFactory
和集合的很类似
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 public final class CollectionTypeAdapterFactory implements TypeAdapterFactory { private final ConstructorConstructor constructorConstructor; public CollectionTypeAdapterFactory (ConstructorConstructor constructorConstructor) { this .constructorConstructor = constructorConstructor; } @Override public <T> TypeAdapter<T> create (Gson gson, TypeToken<T> typeToken) { Type type = typeToken.getType(); Class<? super T> rawType = typeToken.getRawType(); if (!Collection.class.isAssignableFrom(rawType)) { return null ; } Type elementType = $Gson$Types.getCollectionElementType(type, rawType); TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType)); ObjectConstructor<T> constructor = constructorConstructor.get(typeToken); @SuppressWarnings ({"unchecked" , "rawtypes" }) TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor); return result; } private static final class Adapter <E > extends TypeAdapter <Collection <E >> { private final TypeAdapter<E> elementTypeAdapter; private final ObjectConstructor<? extends Collection<E>> constructor; public Adapter (Gson context, Type elementType, TypeAdapter<E> elementTypeAdapter, ObjectConstructor<? extends Collection<E>> constructor) { this .elementTypeAdapter = new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType); this .constructor = constructor; } @Override public Collection<E> read (JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null ; } Collection<E> collection = constructor.construct(); in.beginArray(); while (in.hasNext()) { E instance = elementTypeAdapter.read(in); collection.add(instance); } in.endArray(); return collection; } @Override public void write (JsonWriter out, Collection<E> collection) throws IOException { if (collection == null ) { out.nullValue(); return ; } out.beginArray(); for (E element : collection) { elementTypeAdapter.write(out, element); } out.endArray(); } } }
TypeAdapterRuntimeTypeWrapper
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 @Override public void write (JsonWriter out, T value) throws IOException { TypeAdapter chosen = delegate; Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value); if (runtimeType != type) { TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType)); if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) { chosen = runtimeTypeAdapter; } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) { chosen = delegate; } else { chosen = runtimeTypeAdapter; } } chosen.write(out, value); }
反射类型 ReflectiveTypeAdapterFactory,可以理解为用户自定义的JavaBean对应的Factory。
这是一个通过遍历对象中的属性来进行序列化的adapter。
接口、或者抽象类,不能反序列化(因为不能实例化)
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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { private final ConstructorConstructor constructorConstructor; private final FieldNamingStrategy fieldNamingPolicy; private final Excluder excluder; private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; private final ReflectionAccessor accessor = ReflectionAccessor.getInstance(); public ReflectiveTypeAdapterFactory (ConstructorConstructor constructorConstructor, FieldNamingStrategy fieldNamingPolicy, Excluder excluder, JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory) { this .constructorConstructor = constructorConstructor; this .fieldNamingPolicy = fieldNamingPolicy; this .excluder = excluder; this .jsonAdapterFactory = jsonAdapterFactory; } public boolean excludeField (Field f, boolean serialize) { return excludeField(f, serialize, excluder); } static boolean excludeField (Field f, boolean serialize, Excluder excluder) { return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize); } private List<String> getFieldNames (Field f) { SerializedName annotation = f.getAnnotation(SerializedName.class); if (annotation == null ) { String name = fieldNamingPolicy.translateName(f); return Collections.singletonList(name); } String serializedName = annotation.value(); String[] alternates = annotation.alternate(); if (alternates.length == 0 ) { return Collections.singletonList(serializedName); } List<String> fieldNames = new ArrayList<String>(alternates.length + 1 ); fieldNames.add(serializedName); for (String alternate : alternates) { fieldNames.add(alternate); } return fieldNames; } @Override public <T> TypeAdapter<T> create (Gson gson, final TypeToken<T> type) { Class<? super T> raw = type.getRawType(); if (!Object.class.isAssignableFrom(raw)) { return null ; } ObjectConstructor<T> constructor = constructorConstructor.get(type); return new Adapter<T>(constructor, getBoundFields(gson, type, raw)); } private Map<String, BoundField> getBoundFields (Gson context, TypeToken<?> type, Class<?> raw) { Map<String, BoundField> result = new LinkedHashMap<String, BoundField>(); if (raw.isInterface()) { return result; } Type declaredType = type.getType(); while (raw != Object.class) { Field[] fields = raw.getDeclaredFields(); for (Field field : fields) { boolean serialize = excludeField(field, true ); boolean deserialize = excludeField(field, false ); if (!serialize && !deserialize) { continue ; } accessor.makeAccessible(field); Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); List<String> fieldNames = getFieldNames(field); BoundField previous = null ; for (int i = 0 , size = fieldNames.size(); i < size; ++i) { String name = fieldNames.get(i); if (i != 0 ) serialize = false ; BoundField boundField = createBoundField(context, field, name, TypeToken.get(fieldType), serialize, deserialize); BoundField replaced = result.put(name, boundField); if (previous == null ) previous = replaced; } if (previous != null ) { throw new IllegalArgumentException(declaredType + " declares multiple JSON fields named " + previous.name); } } type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass())); raw = type.getRawType(); } return result; } private ReflectiveTypeAdapterFactory.BoundField createBoundField ( final Gson context, final Field field, final String name, final TypeToken<?> fieldType, boolean serialize, boolean deserialize) { final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType()); JsonAdapter annotation = field.getAnnotation(JsonAdapter.class); TypeAdapter<?> mapped = null ; if (annotation != null ) { mapped = jsonAdapterFactory.getTypeAdapter( constructorConstructor, context, fieldType, annotation); } final boolean jsonAdapterPresent = mapped != null ; if (mapped == null ) mapped = context.getAdapter(fieldType); final TypeAdapter<?> typeAdapter = mapped; return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) { @SuppressWarnings ({"unchecked" , "rawtypes" }) @Override void write (JsonWriter writer, Object value) throws IOException, IllegalAccessException { Object fieldValue = field.get(value); TypeAdapter t = jsonAdapterPresent ? typeAdapter : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType()); t.write(writer, fieldValue); } @Override void read (JsonReader reader, Object value) throws IOException, IllegalAccessException { Object fieldValue = typeAdapter.read(reader); if (fieldValue != null || !isPrimitive) { field.set(value, fieldValue); } } @Override public boolean writeField (Object value) throws IOException, IllegalAccessException { if (!serialized) return false ; Object fieldValue = field.get(value); return fieldValue != value; } }; } static abstract class BoundField { final String name; final boolean serialized; final boolean deserialized; protected BoundField (String name, boolean serialized, boolean deserialized) { this .name = name; this .serialized = serialized; this .deserialized = deserialized; } abstract boolean writeField (Object value) throws IOException, IllegalAccessException ; abstract void write (JsonWriter writer, Object value) throws IOException, IllegalAccessException ; abstract void read (JsonReader reader, Object value) throws IOException, IllegalAccessException ; } public static final class Adapter <T > extends TypeAdapter <T > { private final ObjectConstructor<T> constructor; private final Map<String, BoundField> boundFields; Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) { this .constructor = constructor; this .boundFields = boundFields; } @Override public T read (JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null ; } T instance = constructor.construct(); try { in.beginObject(); while (in.hasNext()) { String name = in.nextName(); BoundField field = boundFields.get(name); if (field == null || !field.deserialized) { in.skipValue(); } else { field.read(in, instance); } } } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } catch (IllegalAccessException e) { throw new AssertionError(e); } in.endObject(); return instance; } @Override public void write (JsonWriter out, T value) throws IOException { if (value == null ) { out.nullValue(); return ; } out.beginObject(); try { for (BoundField boundField : boundFields.values()) { if (boundField.writeField(value)) { out.name(boundField.name); boundField.write(out, value); } } } catch (IllegalAccessException e) { throw new AssertionError(e); } out.endObject(); } } }
小结 源码差不多就到这里了,还有很多Gson的细节、以及扩展性的地方,就不在这里深入讨论了。
捋一下大体流程
根据对象的Type,由Factory创建adapter
创建adapter的过程中,会递归对内部属性创建adapter – 可选,不同Type逻辑不同
委托adapter读写json
源码中比较难看懂的是有很多工厂类、委托类,如果能理清大体的逻辑,就比较容易触类旁通了。
to be continued…
Jackson
FastJson
其他序列化
性能对比 比较简单粗暴地对比..
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 @Slf 4jpublic class PerformanceComparison { @Test public void testPerformance () throws IOException { StopWatch stopWatch = new StopWatch(); stopWatch.start("mock list" ); List<People> peoples = Lists.newArrayList(); int cnt = 10 ; for (int i = 0 ; i < cnt; i++) { People people = new People(); people.setAge(i); people.setName("lily" + i); people.setNicknames(Lists.newArrayList("nick1-" + i, "nick2-" + i)); People friend = new People(); friend.setName("friend" ); people.setFriends(Maps.newHashMap("friend" , friend)); peoples.add(people); } stopWatch.stop(); stopWatch.start("print" ); log.info("peoples = {}" , peoples); stopWatch.stop(); Gson gson = new Gson(); stopWatch.start("gson toJson" ); String json = gson.toJson(peoples); stopWatch.stop(); log.info("gson toJson = {}" , json); stopWatch.start("serialization " ); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("performance.txt" )); outputStream.writeObject(peoples); stopWatch.stop(); log.info("\n{}" , stopWatch.prettyPrint()); } }
结果
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 16:19:56.483 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 10 StopWatch '': running time = 26069677 ns --------------------------------------------- ns % Task name --------------------------------------------- 002320593 009% mock list 006721048 026% gson toJson 017028036 065% serialization 16:19:56.521 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 100 StopWatch '': running time = 32385670 ns --------------------------------------------- ns % Task name --------------------------------------------- 000322435 001% mock list 016472014 051% gson toJson 015591221 048% serialization 16:19:56.611 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 1000 StopWatch '': running time = 89620834 ns --------------------------------------------- ns % Task name --------------------------------------------- 001630599 002% mock list 022239885 025% gson toJson 065750350 073% serialization 16:19:57.315 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 10000 StopWatch '': running time = 703038881 ns --------------------------------------------- ns % Task name --------------------------------------------- 005390392 001% mock list 033934519 005% gson toJson 663713970 094% serialization 16:20:03.333 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 100000 StopWatch '': running time = 6017844063 ns --------------------------------------------- ns % Task name --------------------------------------------- 074621832 001% mock list 181025115 003% gson toJson 5762197116 096% serialization
10次的平均:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16:36:16.309 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 10 16:36:16.316 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - gson = 6ms 16:36:16.316 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - serial = 3ms 16:36:16.406 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 100 16:36:16.406 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - gson = 1ms 16:36:16.406 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - serial = 7ms 16:36:17.025 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 1000 16:36:17.026 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - gson = 3ms 16:36:17.026 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - serial = 58ms 16:36:21.700 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 10000 16:36:21.701 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - gson = 16ms 16:36:21.701 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - serial = 450ms 16:37:14.224 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - cnt = 100000 16:37:14.224 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - gson = 122ms 16:37:14.224 [main] INFO wyq.learning.quickstart.serialization.PerformanceComparison - serial = 5123ms
可以看出来,个数越多,性能差异越明显。
Mock小工具 仿Gson反序列化的逻辑,比较简单的Mock工具,可以支持常见的JavaBean的对象Mock,省去一一手工创建对象、赋值的麻烦。
ps如果对数值有要求,还是要后续自己赋值的。这个小工具的初衷是ut测试时,程序中对属性有非空校验。
pps暂未实现全部的类型
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 @Slf 4jpublic class SimpleMock { @SuppressWarnings ("unchecked" ) public static <T, TT> T mockOf (Type type) { Class<? super T> rawType = (Class<? super T>) getRawType(type); Object object = null ; if (rawType == String.class) { object = "mock" + RandomUtils.nextInt(); } else if (rawType == Long.class || rawType == long .class) { object = RandomUtils.nextLong(); } else if (rawType == Integer.class || rawType == int .class) { object = RandomUtils.nextInt(); } else if (rawType == BigDecimal.class) { object = BigDecimal.valueOf(RandomUtils.nextFloat()).setScale(2 , RoundingMode.HALF_UP); } else if (rawType == Date.class) { object = new Date(); } else if (type instanceof GenericArrayType || type instanceof Class && ((Class) type).isArray()) { Type componentType = type instanceof GenericArrayType ? ((GenericArrayType) type).getGenericComponentType() : ((Class) type).getComponentType(); if (componentType == type) { return null ; } Class<TT> rawComponentType = (Class<TT>) getRawType(componentType); List<TT> list = new ArrayList<TT>(); for (int i = 0 , num = RandomUtils.nextInt(1 , 5 ); i < num; i++) { TT instance = mockOf(rawComponentType); list.add(instance); } Object array = Array.newInstance(rawComponentType, list.size()); for (int i = 0 ; i < list.size(); i++) { Array.set(array, i, list.get(i)); } object = array; } else if (Collection.class.isAssignableFrom(rawType)) { Type elementType = type instanceof ParameterizedType ? ((ParameterizedType) type).getActualTypeArguments()[0 ] : Object.class; if (elementType == type) { return null ; } Collection<TT> collection = construct(rawType); for (int i = 0 , size = RandomUtils.nextInt(1 , 5 ); i < size; i++) { collection.add(mockOf((Class<TT>) elementType)); } object = collection; } else if (Map.class.isAssignableFrom(rawType)) { log.info("map ignored" ); } else if (Object.class.isAssignableFrom(rawType)) { try { T t = (T) rawType.getDeclaredConstructor().newInstance(); Field[] fields = rawType.getDeclaredFields(); for (Field field : fields) { Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType && ((ParameterizedType) fieldType).getActualTypeArguments()[0 ] == type) { log.info("cycle ignored" ); continue ; } TT value = mockOf(fieldType); field.setAccessible(true ); field.set(t, value); } object = t; } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { e.printStackTrace(); } } if (object == null ) { return null ; } return (T) object; } @SuppressWarnings ("unchecked" ) private static <T> T construct (Class<? super T> rawType) { if (Collection.class.isAssignableFrom(rawType)) { if (SortedSet.class.isAssignableFrom(rawType)) { return (T) new TreeSet<Object>(); } else if (Set.class.isAssignableFrom(rawType)) { return (T) new LinkedHashSet<Object>(); } else if (Queue.class.isAssignableFrom(rawType)) { return (T) new ArrayDeque<Object>(); } else { return (T) new ArrayList<Object>(); } } if (Map.class.isAssignableFrom(rawType)) { return (T) new LinkedHashMap<Object, Object>(); } return null ; } @Test public void test () { Gson gson = new Gson(); Product product = SimpleMock.mockOf(Product.class); log.info("product = {}" , gson.toJson(product)); List<Product> products = SimpleMock.mockOf(new TypeToken<List<Product>>() { }.getType()); log.info("products = {}" , gson.toJson(products)); } @Data public static class Product { private Long id; private String name; private List<String> list; private List<Product> products; private Integer[] integers; } }
参考
Java序列化
Java 序列化和反序列化的几篇文章
Gson源码解析和它的设计模式