作者简介:ASCE1885, 《Android 高级进阶》作者。
本文由于潜在的商业目的,未经授权不开放全文转载许可,谢谢!
本文分析的源码版本已经 fork 到我的 Github。
通过前面一篇文章的介绍,我们知道 Serial 框架的核心是 Serializer 类,对象的序列化和反序列化都是通过重写这个类的方法实现的,因此我们就以 Serializer 类为起点来开始源码的剖析,首先来看下这个类的继承体系:
读过前面一篇文章的同学对这几个类应该都有印象,这里再简单总结一下:
- Serializer:抽象基类,一切的开始
- ObjectSerializer:通过在序列化时增加版本号信息从而提供向后兼容性
- BuilderSerializer:继承自 ObjectSerializer,支持在反序列化时通过 Builder 模式构造对象
- ValueSerializer:不包含版本号信息,只处理简单数据类型,不考虑向后兼容性
同时,为了让框架使用者少写样板代码,Serial 还提供 CoreSerializers 和 CollectionSerializers 两个类,分别针对常用的数据类型和集合定义了一系列默认 Serializer 类。下面我们来一一分析。
Serializer
所有 Serializer 的抽象基类,定义了最基础的序列化和反序列化整体框架,我们直接来看代码和注释:
public abstract class Serializer<T> {
/**
* 序列化方法
* @param context 序列化上下文信息
* @param output 序列化输出流
* @param object 要序列化的对象实例
* @throws IOException
*/
public abstract void serialize(@NotNull SerializationContext context,
@NotNull SerializerOutput output, @Nullable T object) throws IOException;
/**
* 反序列化方法,反序列化后生成的对象可能为空
* @param context 序列化上下文信息
* @param input 序列化输入流
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
@Nullable
public abstract T deserialize(@NotNull SerializationContext context,
@NotNull SerializerInput input) throws IOException, ClassNotFoundException;
/**
* 当反序列化后生成的对象为空时将抛出异常
* @param context 序列化上下文信息
* @param input 序列化输入流
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
@NotNull
public final T deserializeNotNull(@NotNull SerializationContext context,
@NotNull SerializerInput input) throws IOException, ClassNotFoundException {
final T deserializedObject = deserialize(context, input);
return InternalSerialUtils.checkIsNotNull(deserializedObject);
}
}
其中涉及到其他几个重要的类:
- SerializationContext:序列化相关上下文信息,下面会进一步介绍
- SerializerInput:序列化输入流,从序列化后的数据中读取指定类型信息的通道,反序列化时使用,我们将会在下一篇文章集中介绍,在这里读者只需要理解它的作用就行
- SerializerOutput:序列化输出流,将对象指定类型属性信息写入到其他介质(磁盘等)中的通道,序列化时使用,同样会在下一篇文章介绍
SerializationContext 用于保存序列化过程中的环境信息,目前提供两个方法分别来判断当前是开发环境和线上发布环境,同时提供一个默认的实现类,代码如下:
public interface SerializationContext {
/**
* 线上发布环境下的默认实现
*/
SerializationContext ALWAYS_RELEASE = new SerializationContext() {
@Override
public boolean isDebug() {
return false;
}
@Override
public boolean isRelease() {
return true;
}
};
/**
* 返回 true 表示当前是开发环境,某些序列化和反序列化操作会被执行(例如调试信息的保存)
* @return
*/
boolean isDebug();
/**
* 返回 true 表示当前是线上发布环境
* @return
*/
boolean isRelease();
}
可以看到,isDebug 和 isRelease 本质上是互斥的,因此,更好的实现是保留一个即可,没必要在增加复杂度的情况下没有得到其他任何好处。当然,随着后面框架的迭代升级,SerializationContext 可能会增加更多其他的环境上下文相关信息。
让我们回到 Serializer 类的实现中,可以看到有两个反序列化的方法,deserialize 和 deserializeNotNull,后者是在前者执行结果的基础上增加对反序列化后对象是否为空的校验,如果为空则抛出异常,使用者可以根据具体业务需求选用,为空校验在 InternalSerialUtils.checkIsNotNull 方法中,代码如下:
@NotNull
@Contract("null -> fail")
public static <T> T checkIsNotNull(@Nullable T value) {
if (!(value != null)) {
throw new AssertionError("Assertion failed.");
}
return value;
}
可以看到代码中使用双重否定来判断 value 是否为空,这段代码同样显得画蛇添足,直接判断 value == null 即可。