// …1110 & …1101 = …1100,次低位0表示第二个默认字段在json中存在,不需要赋默认,以此类推
mask0 = mask0 and 0xfffffffd.toInt()
}
2 -> age = intAdapter.fromJson(reader) ?: throw Util.unexpectedNull(“age”, “age”, reader)
-1 -> {
// Unknown name, skip it.
reader.skipName()
reader.skipValue()
}
}
}
reader.endObject()
if (mask0 == 0xfffffffc.toInt()) {
// 如果所有默认字段都存在于json中,则忽略默认值直接调用构造函数赋值成json中的值
return DefaultPart(
name = name as String,
gender = gender as String,
// age字段非空,如果在json中没有对应key则抛异常
age = age ?: throw Util.missingProperty(“age”, “age”, reader)
)
} else {
// 如果有默认值的字段在Json中不存在,则传入flag反射调用synthetic构造函数,填充默认值
@Suppress(“UNCHECKED_CAST”)
val localConstructor: Constructor = this.constructorRef ?:
DefaultPart::class.java.getDeclaredConstructor(String::class.java, String::class.java,
Int::class.javaPrimitiveType, Int::class.javaPrimitiveType,
Util.DEFAULT_CONSTRUCTOR_MARKER).also { this.constructorRef = it }
return localConstructor.newInstance(
name,
gender,
age ?: throw Util.missingProperty(“age”, “age”, reader),
mask0,
/* DefaultConstructorMarker */ null
)
}
}
}
做的事情其实也很简单,代码中我写了注释
- 用一个int记录(字段超过32个使用多个int)默认值字段在将要解析的json中是否存在,从最低位到最高位依次记录第一个到最后一个默认值字段在json中是否有key,0表示存在,1表示不存在
- 判断是否所有默认字段在json中都有值,若为true则不用管默认值,直接使用json字段生成实例,若为false则反射调用(synthetic构造器只能够反射调用)synthetic构造器实例化对象,synthetic构造器会根据标志位为默认值字段赋值
一言蔽之,Moshi通过遵循Kotlin的机制做到了兼容。
解决方案
分析了这么多,避免默认值无效的方法已经显而易见了
- 定义类时所有字段都给一个默认值,这样gson就可以正常工作
- 使用Moshi库
其他问题,Json中value为null的情况
正常情况下后端返回的Json数据中只应该存在Object类型字段为null的情况,但是现实很骨感,不乏String类型/list类型丢过来也是null的情况。
- 在Java中,null value会覆盖掉默认值,使用时get方法中判空就可以了。
- 但是在Kotlin中,如果该字段声明为非空类型,使用gso