我有一个 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()使用反射,所以速度有点慢。
我想知道这是否是实现这一目标的最佳/唯一方法,或者是否有一种不使用反射的方法可以更有效。
如果您想使用您链接的 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)