Kotlin Android Room如何在Moshi TypeConverter中处理空对象列表

3

我接手了一个Android项目,需要将rxJava代码转换为更加纯粹的Kotlin中心代码,并采用MVVM设计模式。虽然经验有限,我花费了很多时间和精力,最终完成了代码转换。但是,尽管测试进行得相当顺利,新的@TypeConverters似乎更加严格,不允许存储Room数据库中期望对象的空列表。
当数据从服务器加载并且项目soil_types为空,如soil_types=[]时,我会收到错误消息:Expected receiver of type models.SoilType, but got java.util.ArrayList.
以下是转换器的代码:

@TypeConverter
fun fromJson(json: String?): List<SoilType>? {
    if(json == null) return null
    return convertJsonToListObject(json)
}

@TypeConverter
fun toJson(objectData: List<SoilType>?): String? {
    if (objectData == null) return null
    return convertListObjectToJson(objectData)
}
//...
inline fun <reified T> convertJsonToListObject(json: String): List<T> =
    moshi.adapter<List<T>>(T::class.java).fromJson(json).orEmpty()

inline fun <reified T> convertListObjectToJson(objectData: List<T>): String =
    moshi.adapter<List<T>>(T::class.java).toJson(objectData)

以下是需要填充的房间模型:

@Entity(tableName = "soil")
data class Soil(
        @PrimaryKey val id: Long,
        val user_id: Long,
        val name: String,
        val soil_types: List<SoilType>,
        val updated_at: String,
        val created_at: String
)

我知道这不是一个好的数据表列设计和可能建立的关系。

我的问题是如何让转换器接受空ArrayList,这样我就可以将emptyList保存为类似'{}'的字符串?或者,如果我不想这样做,应该允许null吗?

编辑:
我尝试将转换器更改为以下内容:

@TypeConverter
fun fromJson(json: String?): List<SoilType> {
    if(json == null || json == "{}") return emptyList()
    return convertJsonToListObject(json)
}

@TypeConverter
fun toJson(objectData: List<SoilType>?): String {
    if (objectData.isNullOrEmpty()) return "{}"
    return convertListObjectToJson(objectData)
}

但错误仍然存在。

编辑2:
似乎我正在经历的是内置于 Moshi json库中的。在进一步阅读Moshi handling of null and absent JSON fields部分后,看起来必须为数据类字段声明默认值才能获得预期结果:

如果JSON响应更改并在JSON中设置空字段,则适配器将失败,尊重数据类中val属性的非null引用,并抛出明确的异常。

在这种情况下,是一个空的对象列表。


那么你找到了解决方案?如果是的话,我建议发表一个答案 :) - user3738870
@user3738870 目前还没有解决方案。我找到了一个可能导致问题的参考资料,但是到目前为止,我所有的测试都没有成功。 - Hmerman6006
1
我已经尝试过这个方法,当我在创建适配器时将T::class.java更改为Types.newParameterizedType(List::class.java, T::class.java)时,它对我有效。你可以尝试一下吗? - user3738870
1
@user3738870,太棒了!非常感谢你。我尝试了很多不同的解决方案,但是你的第一次就成功了。如果你把你的评论作为答案,我会标记它的。 - Hmerman6006
1个回答

1

问题实际上不在Room中,而是在Moshi中。根据其文档,您需要按照以下步骤来解析JSON列表:

inline fun <reified T> convertJsonToListObject(json: String): List<T> =
    moshi.adapter<List<T>>(Types.newParameterizedType(List::class.java, T::class.java)).fromJson(json).orEmpty()

inline fun <reified T> convertListObjectToJson(objectData: List<T>): String =
    moshi.adapter<List<T>>(Types.newParameterizedType(List::class.java, T::class.java)).toJson(objectData)

还有一种特定于Kotlin的方法可以实现这一点,但在Moshi的最新版本(1.13.0)中,您仍然需要选择此功能:

import com.squareup.moshi.adapter

@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> convertJsonToListObject(json: String): List<T> =
    moshi.adapter<List<T>>().fromJson(json).orEmpty()

@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> convertListObjectToJson(objectData: List<T>): String =
    moshi.adapter<List<T>>().toJson(objectData)

可以说,这只会使你的代码更加复杂,因此在使用这个针对Kotlin的解决方案之前,等待一段时间可能是值得的。


1
只是想补充一点,如果我的问题第一个编辑中的 @TypeConverter 方法没有添加到最终代码中;那么 Moshi 适配器将把空列表保存为 [] 而不是 {}。我还编辑了标题和标签以适应答案。 - Hmerman6006
1
是的,[] 是一个空的 JSON 数组,这通常是我们希望将空列表映射到的内容。 - user3738870

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接