首先感谢这位老哥的方法
我定义了data class的属性为val 且都不为null,都有默认值,这样子避免UI页面显示出问题,而且拿取属性的时候,不需要判空,使用也方便。
按道理,json解析的时候,遇到value为null的时候,应该使用默认值,但是呢,gson却给赋值了null进去,是的,是null,明明定义这个属性不为null且有默认值,然后ide提示你这个属性又一定不为null,所以,当请求结果有某个属性是null的时候,直接使用的话,就会崩溃。
你又不可能每个属性在使用的时候都要判空,或者把属性声明成可为null的?,这样工作量有点大,也不符合自己的预期。
网上大佬解释是,拿不到class的无参构造函数,会使用不安全的反射方式创建对象,再赋值,在解析的时候,遇到字段是null,直接赋值null。然后,我把data class改成class也是一样不可行,把构造函数参数全挪成全局属性也不行。
然后看了老哥的方法,试了一下,没有崩溃了,好像是解决了。
fun gsonNullToDefault(): Gson = GsonBuilder()
.registerTypeAdapterFactory(GsonDefaultAdapterFactory())
.create()
class GsonDefaultAdapterFactory: TypeAdapterFactory {
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.type == String::class.java) {
return createStringAdapter()
}
if (type.rawType == List::class.java || type.rawType == Collection::class.java) {
return createCollectionAdapter(type, gson)
}
return null
}
/**
* null替换成空List
*/
private fun <T : Any> createCollectionAdapter(
type: TypeToken<T>,
gson: Gson
): TypeAdapter<T>? {
val rawType = type.rawType
if (!Collection::class.java.isAssignableFrom(rawType)) {
return null
}
val elementType: Type = `$Gson$Types`.getCollectionElementType(type.type, rawType)
val elementTypeAdapter: TypeAdapter<Any> =
gson.getAdapter(TypeToken.get(elementType)) as TypeAdapter<Any>
return object : TypeAdapter<Collection<Any>>() {
override fun write(writer: JsonWriter, value: Collection<Any>?) {
writer.beginArray()
value?.forEach {
elementTypeAdapter.write(writer, it)
}
writer.endArray()
}
override fun read(reader: JsonReader): Collection<Any> {
val list = mutableListOf<Any>()
// null替换为空list
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return list
}
reader.beginArray()
while (reader.hasNext()) {
val element = elementTypeAdapter.read(reader)
list.add(element)
}
reader.endArray()
return list
}
} as TypeAdapter<T>
}
/**
* null 替换成空字符串
*/
private fun <T : Any> createStringAdapter(): TypeAdapter<T> {
return object : TypeAdapter<String>() {
override fun write(writer: JsonWriter, value: String?) {
if (value == null) {
writer.value("")
} else {
writer.value(value)
}
}
override fun read(reader: JsonReader): String {
// null替换为""
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return ""
}
return reader.nextString()
}
} as TypeAdapter<T>
}
}
然后在retrofit解析拦截器里,稍微改一下即可
.addConverterFactory(GsonConverterFactory.create(gsonNullToDefault()))
在使用kotlin的时候,最好使用这个gsonNullToDefault()解析json
再次感谢这个老哥拯救了我