Android Kotlin Moshi:Moshi 的自定义适配器不起作用

问题描述 投票:0回答:1

我有一个 json 可以有两个可能的值

{"school.name": "A school name"}

{"name": "Another school name"}

我有一个通用的“College”类来序列化/反序列化两者。

使用 Gson,我可以设置这样的注释:

@SerializedName(
    value = "school.name",
    alternate = ["name"]
)

但我目前正在搬到 Moshi,我无法复制这种行为。

我的“College”课程与适配器如下所示:

@JsonClass(generateAdapter = false)
internal class CollegeUS(
    @Json(name = "school.name")
    val college: String?
) {

    @JsonClass(generateAdapter = false)
    class CollegeWorldwide(
        @Json(name = "name")
        val college: String?
    )

    companion object {
        val JSON_ADAPTER: Any = object : Any() {
            @ToJson
            private fun toJson(collegeWorldwide: String): String {
                throw NotImplementedError("Required to make test pass")
            }

            @FromJson
            private fun fromJson(collegeWorldwide: CollegeWorldwide): CollegeWorldwide {
                if (collegeWorldwide.college != null) return CollegeWorldwide(collegeWorldwide.college)
                throw JsonDataException("No school.name or name key found.")
            }
        }
    }
}

我的目标显然是根据输入字符串 json 返回一个 CollegeUS 实例,其中“college”属性具有相应的 json 值。

我正在用这段代码进行测试:

val collegeUS = "{\"school.name\": \"US\"}"
val collegeWorldwide = "{\"name\": \"Worldwide\"}"

val oCollegeUS = collegeUS.toCollege()
val oCollegeWorldwide = collegeWorldwide.toCollege()

这个扩展:

private fun String.toCollege(): CollegeUS.CollegeWorldwide? {
    val moshi = Moshi.Builder().add(CollegeUS.JSON_ADAPTER).addLast(KotlinJsonAdapterFactory()).build()
    val adapter = moshi.adapter(CollegeUS.CollegeWorldwide::class.java)
    return adapter.fromJson(this)
}

但是这种方式仅适用于 CollegeWorldwide json。

我确信我在定义/实现适配器时做错了什么,但我是 Moshi 的新手,所以不知道是什么。

编辑:

澄清一下,我期望与 Gson 的行为完全相同,只是一门 CollegeUS 课程。 CollegeWorldwide 是在下面给出的示例中他所说的“中级”(我只是想有一个更合适的名称),但我希望最终只有 CollegeUS。

我从这里

获取了示例代码

编辑2:

为了进一步澄清:

我在这里只为 CollegeUS 设置了一个属性来简化,但是 - 考虑到整个班级 - 来自接下来的两个可能的 json:

{
    "name" : "Any college",
    "state-province" : "Any province", 
    "country" : "Any country",
    "page" : "1"
}

{
    "college_name" : "Any college",
    "state" : "Any state",
    "page" : "1"
}

我需要获取一个具有相应属性的“CollegeUS”实例(当 json 中没有此类属性时为 null 或空字符串)。

我遵循了下面粘贴的代码,因为这是我发现完成我需要的唯一方法,但根据@Marcono1234,我必须使用“KotlinJsonAdapterFactory()”,如果我没有错的话 KotlinJsonAdapterFactory()使用反射,所以速度有点慢。

我想知道这是否是实现这一目标的最佳/唯一方法,或者是否有一种不使用反射的方法可以更有效。

android json kotlin gson moshi
1个回答
0
投票

如果您想使用您链接的 GitHub 问题中所示的中间类,则该中间类需要两个字段。然后,确实将类称为

...Intermediate
(或类似的)可能更有意义,因为它实际上就是这样,一个具有同一字段的两个属性的中间表示。所以它既不是“美国学院”也不是“世界学院”,而是两者的结合。

因此您的代码可能如下所示:

@JsonClass(generateAdapter = false)
internal class CollegeUS(
    val college: String
) {
    @JsonClass(generateAdapter = false)
    class CollegeIntermediate(
        // Name can be either provided as `name` or as `school.name` property
        val name: String?,
        @Json(name = "school.name")
        val schoolName: String?
    )

    companion object {
        val JSON_ADAPTER: Any = object : Any() {
            @FromJson
            private fun fromJson(collegeIntermediate: CollegeIntermediate): CollegeUS {
                val name = collegeIntermediate.name ?: collegeIntermediate.schoolName
                    ?: throw JsonDataException("No school.name or name key found.")

                return CollegeUS(name)
            }
        }
    }
}

然后您可以像这样使用它:

val moshi = Moshi.Builder()
    .add(CollegeUS.JSON_ADAPTER)
    .addLast(KotlinJsonAdapterFactory())
    .build()
val adapter = moshi.adapter(CollegeUS::class.java)
println(adapter.fromJson("{\"name\": \"US\"}")?.college)
© www.soinside.com 2019 - 2024. All rights reserved.