基本使用
Kotlin
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val xxx = moshi.adapter(XXXX::class.java).fromJson(jsonstring)
- @Json(name="xxx") 设置别名
- @Json(ignore = true) 忽略字段
- @JsonClass(generateAdapter=true)编译生成JsonAdapter
初始化
Java
Moshi(Builder builder) {
List<JsonAdapter.Factory> factories =
new ArrayList<>(builder.factories.size() + BUILT_IN_FACTORIES.size());
factories.addAll(builder.factories);
factories.addAll(BUILT_IN_FACTORIES);
this.factories = Collections.unmodifiableList(factories);
this.lastOffset = builder.lastOffset;
}
// 内置 Factory 初始化
static {
BUILT_IN_FACTORIES.add(StandardJsonAdapters.FACTORY);
BUILT_IN_FACTORIES.add(CollectionJsonAdapter.FACTORY);
BUILT_IN_FACTORIES.add(MapJsonAdapter.FACTORY);
BUILT_IN_FACTORIES.add(ArrayJsonAdapter.FACTORY);
BUILT_IN_FACTORIES.add(RecordJsonAdapter.FACTORY);
BUILT_IN_FACTORIES.add(ClassJsonAdapter.FACTORY);
}
- 添加 Builder 中配置的 Factory
- 添加内置的 Factory
JsonClass 注解
- 编译期间为类型生成默认的 JsonAdapter
- 只能用于 Kotlin class,如果有父类也必须是 Kotlin class
JsonAdapter查找
Moshi.adapter(type),查找处理指定类型的 JsonAdapter
Java
public <T> JsonAdapter<T> adapter(
Type type, Set<? extends Annotation> annotations, @Nullable String fieldName) {
// 缓存
Object cacheKey = cacheKey(type, annotations);
synchronized (adapterCache) {
JsonAdapter<?> result = adapterCache.get(cacheKey);
if (result != null) return (JsonAdapter<T>) result;
}
LookupChain lookupChain = lookupChainThreadLocal.get();
if (lookupChain == null) {
lookupChain = new LookupChain();
lookupChainThreadLocal.set(lookupChain);
}
boolean success = false;
JsonAdapter<T> adapterFromCall = lookupChain.push(type, fieldName, cacheKey);
try {
// Lookup 没获取到,新的查询
if (adapterFromCall != null) return adapterFromCall;
// 遍历factory创建JsonAdapter
for (int i = 0, size = factories.size(); i < size; i++) {
JsonAdapter<T> result = (JsonAdapter<T>) factories.get(i).create(type, annotations, this);
if (result == null) continue;
// 查找成功,修改 Lookup 的 adapter
lookupChain.adapterFound(result);
success = true;
return result;
}
}
}
<T> JsonAdapter<T> push(Type type, @Nullable String fieldName, Object cacheKey) {
for (int i = 0, size = callLookups.size(); i < size; i++) {
Lookup<?> lookup = callLookups.get(i);
if (lookup.cacheKey.equals(cacheKey)) {
Lookup<T> hit = (Lookup<T>) lookup;
stack.add(hit);
// 存在查找,返回具体 JsonAdapter 或者代理 Lookup
return hit.adapter != null ? hit.adapter : hit;
}
}
// 首次查找,创建 Lookup 并保存
Lookup<Object> lookup = new Lookup<>(type, fieldName, cacheKey);
callLookups.add(lookup);
stack.add(lookup);
return null;
}
- 查找缓存;
- 获取 LookupChain;
- 调用 LookupChain.push 提交查询;
- 如果当前没有相同类型的查询则创建 LookUp 类型,保存并返回;
- LookUp相当于JsonAdapter的代理对象,本身继承了JsonAdapter,内部持有一个 JsonAdapter 成员,次成员是最终查找到的实际 Adapter,序列化及反序列化委托给次成员实现;
- 如果当前存在相同类型的查询,获取其对应的 Lookup 对象,如果其中的 adpter 不为空,返回代理的JsonAdapter,否则返回 Lookup 自身;
- 如果 LookUpChain.push 返回不为 null,表明查找到了,否则遍历初始化 Moshi 是配置的 factories 列表,调用其 create 方法并传递类型信息,如果 create 返回非空,表示查找到了;
- 通知 LookupChain 找到 adppter了,对 LookUp 设置 adapter;
- 总结:本身逻辑应该比较简单,缓存查不到直接通过 factory 创建就好了,但是这边加了一个 LookUp 的代理逻辑,这个主要是为了解决循环依赖的问题,比如有 A 和 B 两个类型,A中包含一个B类型的成员,B中包含一个A类型的成员,这时候查找A的JsonAdapter的过程中会去查找B的JsonAdapter,那在查找B的JsonAdapter同时又依赖了A的JsonAdapter,这样就循环依赖了。通过 LookUp 代理,在查找A的时候插入了一个LookUp 代理,没找到A走创建,创建过程中查找B,B也没有同样走创建,创建B的时候查找A返回了A的Lookup对象,这样B创建完成,返回继续A的创建,A创建完了把Lookup中的adapter替换。
反序列化Java对象
由内置的 ClassJsonAdapter 完成
ini
public T fromJson(JsonReader reader) throws IOException {
T result;
try {
result = classFactory.newInstance();
}
// 身略 catch
try {
reader.beginObject();
while (reader.hasNext()) {
int index = reader.selectName(options);
if (index == -1) {
reader.skipName();
reader.skipValue();
continue;
}
fieldsArray[index].read(reader, result);
}
reader.endObject();
return result;
} catch (IllegalAccessException e) {
throw new AssertionError();
}
}
内部通过 ClassFactory 创建出对象,在读取属性赋值
Java
// 1、获取无参构造方法,反射创建对象
try {
final Constructor<?> constructor = rawType.getDeclaredConstructor();
constructor.setAccessible(true);
return new ClassFactory<T>() {
@Override
public T newInstance()
throws IllegalAccessException, InvocationTargetException, InstantiationException {
Object[] args = null;
return (T) constructor.newInstance(args);
}
@Override
public String toString() {
return rawType.getName();
}
};
} catch (NoSuchMethodException ignored) {
}
// 2、通过 Unsafe 的 allocateInstance 创建对象
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field f = unsafeClass.getDeclaredField("theUnsafe");
f.setAccessible(true);
final Object unsafe = f.get(null);
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
return new ClassFactory<T>() {
public T newInstance() throws InvocationTargetException, IllegalAccessException {
return (T) allocateInstance.invoke(unsafe, rawType);
}
@Override
public String toString() {
return rawType.getName();
}
};
}
- 反射获取类的无参构造方法,通过无参构造方法创建对象;
- 如果没有无参数的构造方法,则反射获取 Unsafe 实例,调用其 allocateInstance 创建对象;
- 整体过Gson比较类似;
反序列化Kotlin对象
由 moshi-kotlin 模块的 KotlinJsonAdapter 完成,通常需要在初始化 Moshing 的时候手动添加 KotlinJsonAdapterFactory
尝试从@JsonClass
注解生成的JsonAdapter中查找匹配的
- 判断是否含有 JsonClass 注解,并且设置了 generateAdapter = true;
- 根据类型名拼JsonAdapter字符串得到此类型生成的 JsonAdapter 类型名称,eg:UserInfoJsonAdapter;
- Class.formName加载对应的JsonAdapter,反射构造方法创建对象并返回;
Java
public static @Nullable JsonAdapter<?> generatedAdapter(
Moshi moshi, Type type, Class<?> rawType) {
JsonClass jsonClass = rawType.getAnnotation(JsonClass.class);
// 包含注解并且 generateAdapter 设置为 true
if (jsonClass == null || !jsonClass.generateAdapter()) {
return null;
}
// 生成类型的名称
String adapterClassName = Types.generatedJsonAdapterName(rawType.getName());
Class<? extends JsonAdapter<?>> adapterClass = null;
try {
// 反射获取类型
adapterClass =
(Class<? extends JsonAdapter<?>>)
Class.forName(adapterClassName, true, rawType.getClassLoader());
Constructor<? extends JsonAdapter<?>> constructor;
Object[] args;
if (type instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) type).getActualTypeArguments();
try {
// Common case first
constructor = adapterClass.getDeclaredConstructor(Moshi.class, Type[].class);
args = new Object[] {moshi, typeArgs};
} catch (NoSuchMethodException e) {
constructor = adapterClass.getDeclaredConstructor(Type[].class);
args = new Object[] {typeArgs};
}
} else {
try {
// Common case first
constructor = adapterClass.getDeclaredConstructor(Moshi.class);
args = new Object[] {moshi};
} catch (NoSuchMethodException e) {
constructor = adapterClass.getDeclaredConstructor();
args = new Object[0];
}
}
constructor.setAccessible(true);
return constructor.newInstance(args).nullSafe();
}
// catch 逻辑省略
如果没有对应的 JsonAdapter,则通过 Kotlin 的反射生成对象
- 获取 kotlin 主构造方法及其参数列表
- 遍历 class 的成员列表,查找每个成员的 JsonAdapter
- 记录每个成员的名称,对应的 JsonAdapter,是否是构造方法参数,index信息
- 根据收集的信息创建 KotlinJsonAdapter
- KotlinJsonAdapter 中读取 json 数据,根据字段是否有值,是否有默认值,是否可能等条件调用不同的构造方法,完成初始化,
- 存在默认参数的时候,kotlin内部会生成一个构造方法,在方法内部判断如果默认值参数没传递则使用默认值。
Java
// KotlinJsonAdapter
override fun fromJson(reader: JsonReader): T {
val constructorSize = constructor.parameters.size
// Read each value into its slot in the array.
val values = Array<Any?>(allBindings.size) { ABSENT_VALUE }
reader.beginObject()
while (reader.hasNext()) {
val index = reader.selectName(options)
if (index == -1) {
reader.skipName()
reader.skipValue()
continue
}
val binding = nonIgnoredBindings[index]
val propertyIndex = binding.propertyIndex
if (values[propertyIndex] !== ABSENT_VALUE) {
throw JsonDataException(
"Multiple values for '${binding.property.name}' at ${reader.path}"
)
}
// 保存从json中解析出来的属性值
values[propertyIndex] = binding.adapter.fromJson(reader)
reader.endObject()
// Confirm all parameters are present, optional, or nullable.
// Class 成员数量 == 构造方法参数数量
var isFullInitialized = allBindings.size == constructorSize
for (i in 0 until constructorSize) {
// 构造函数参数成员没有从 json 中解析出值
if (values[i] === ABSENT_VALUE) {
when {
// 可选的,存在默认值
constructor.parameters[i].isOptional -> isFullInitialized = false
// 可空的,直接设置为null
constructor.parameters[i].type.isMarkedNullable -> values[i] = null
// 异常
else -> throw Util.missingProperty(
constructor.parameters[i].name,
allBindings[i]?.jsonName,
reader
)
}
}
}
val result = if (isFullInitialized) {
// 调用默认构造方法
constructor.call(*values)
} else {
// 调用生成的构造方法(带一个mask参数和一个mark参数,内部做了默认参数的赋值工作)
constructor.callBy(IndexedParameterMap(constructor.parameters, values))
}
// Set remaining properties.
for (i in constructorSize until allBindings.size) {
val binding = allBindings[i]!!
val value = values[i]
binding.set(result, value)
}
return result
}
和Gson比较
- Moshi 对 Kotlin 支持更好,data class、默认值、空安全
- data class 没有默认的无参构造方法,反序列化的时候通过 Unsfae 的方式去创建的实例对象,导致默认值的初始化以及非空值的断言都没有执行