如何在带有枚举的 kotlinjs 中正确使用 JSON.parse?
How to properly use JSON.parse in kotlinjs with enums?
在我使用 kotlin-react 的新冒险中,我在尝试从我的后端解析一些包含枚举值的数据时遇到了困难。
Spring-Boot 以 JSON 形式发送对象,如下所示:
{
"id": 1,
"username": "Johnny",
"role": "CLIENT"
}
role
在这种情况下是枚举值,可以有两个值 CLIENT
和 LECTURER
。如果我要用 java 库解析它,或者让它由 Spring-Boot 处理,role
将被解析为相应的枚举值。
使用 kotlin-js 的 JSON.parse
,那是行不通的,我会在其中有一个简单的字符串值。
经过一些测试,我想到了这个片段
val json = """{
"id": 1,
"username": "Johnny",
"role": "CLIENT",
}"""
val member: Member = JSON.parse(json) { key: String, value: Any? ->
if (key == "role") Member.Role.valueOf(value.toString())
else value
}
其中我必须手动定义从字符串值到枚举的转换。
我是否缺少可以简化此行为的内容?
(我不是指为 JSON 使用 id 和查找它们等。我对 Kotlin-JS 中的某些方法感到好奇)
我假设没有,因为 JS 中的 "original" JSON.parse
没有这样做,Kotlin 也没有在其中添加任何额外的东西,但我仍然有希望!
据我所知,没有。
问题
Kotlin.JS 在使用嵌入式 JSON class 进行反序列化时会产生一种令人难以置信的怪异类型情况,这实际上是一个 mirror for JavaScript's JSON class。虽然我没有做太多 JavaScript,但它的类型处理几乎不存在。只有手动抛出才能强制执行它,所以 JSON.parse
不关心它是 returns 一个 SomeCustomObject
还是一个具有完全相同字段的新创建的对象。
举个例子,如果你有两个不同的 class 具有相同的字段名称(无继承),并且有一个接受变量的函数,它不关心其中的哪一个(或第三个)只要它尝试在 class 上访问的变量存在,它就会收到。
类型问题在 Kotlin 中表现出来。现在将其包装回 Kotlin,考虑以下代码:
val json = """{
"x": 1, "y": "yes", "z": {
"x": 42, "y": 314159, "z": 444
}
}""".trimIndent()
data class SomeClass(val x: Int, val y: String, val z: Struct)
data class Struct(val x: Int, val y: Int, val z: Int)
fun main(args: Array<String>) {
val someInstance = JSON.parse<SomeClass>(json)
if(someInstance.z::class != Struct::class) {
println("Incompatible types: Required ${Struct::class}, found ${someInstance.z::class}");
}
}
您希望打印什么?自然会期待 Struct
。类型也明确声明
不幸的是,事实并非如此。相反,它打印:
Incompatible types: Required class Struct, found class Any
重点
嵌入式 JSON de/serializer 不适用于类型。您可以使用不同的序列化库来解决此问题,但我会避免将其变成 "use [this] library".
本质上,JSON.parse
未能按预期解析对象。如果您完全删除参数并在问题中的 JSON 上尝试使用原始 JSON.parse(json);
,您将得到 role
,即 String
而不是 Role
,你可能会想到。 JSON.parse
没有进行任何类型转换,这意味着您有两个选择:使用库或使用您的方法。
不幸的是,如果您有嵌套对象,您的方法会变得复杂,但是随着类型的改变,您似乎剩下的唯一选择就是手动显式解析对象。
TL;DR:你的方法很好。
在我使用 kotlin-react 的新冒险中,我在尝试从我的后端解析一些包含枚举值的数据时遇到了困难。
Spring-Boot 以 JSON 形式发送对象,如下所示:
{
"id": 1,
"username": "Johnny",
"role": "CLIENT"
}
role
在这种情况下是枚举值,可以有两个值 CLIENT
和 LECTURER
。如果我要用 java 库解析它,或者让它由 Spring-Boot 处理,role
将被解析为相应的枚举值。
使用 kotlin-js 的 JSON.parse
,那是行不通的,我会在其中有一个简单的字符串值。
经过一些测试,我想到了这个片段
val json = """{
"id": 1,
"username": "Johnny",
"role": "CLIENT",
}"""
val member: Member = JSON.parse(json) { key: String, value: Any? ->
if (key == "role") Member.Role.valueOf(value.toString())
else value
}
其中我必须手动定义从字符串值到枚举的转换。
我是否缺少可以简化此行为的内容?
(我不是指为 JSON 使用 id 和查找它们等。我对 Kotlin-JS 中的某些方法感到好奇)
我假设没有,因为 JS 中的 "original" JSON.parse
没有这样做,Kotlin 也没有在其中添加任何额外的东西,但我仍然有希望!
据我所知,没有。
问题
Kotlin.JS 在使用嵌入式 JSON class 进行反序列化时会产生一种令人难以置信的怪异类型情况,这实际上是一个 mirror for JavaScript's JSON class。虽然我没有做太多 JavaScript,但它的类型处理几乎不存在。只有手动抛出才能强制执行它,所以 JSON.parse
不关心它是 returns 一个 SomeCustomObject
还是一个具有完全相同字段的新创建的对象。
举个例子,如果你有两个不同的 class 具有相同的字段名称(无继承),并且有一个接受变量的函数,它不关心其中的哪一个(或第三个)只要它尝试在 class 上访问的变量存在,它就会收到。
类型问题在 Kotlin 中表现出来。现在将其包装回 Kotlin,考虑以下代码:
val json = """{
"x": 1, "y": "yes", "z": {
"x": 42, "y": 314159, "z": 444
}
}""".trimIndent()
data class SomeClass(val x: Int, val y: String, val z: Struct)
data class Struct(val x: Int, val y: Int, val z: Int)
fun main(args: Array<String>) {
val someInstance = JSON.parse<SomeClass>(json)
if(someInstance.z::class != Struct::class) {
println("Incompatible types: Required ${Struct::class}, found ${someInstance.z::class}");
}
}
您希望打印什么?自然会期待 Struct
。类型也明确声明
不幸的是,事实并非如此。相反,它打印:
Incompatible types: Required class Struct, found class Any
重点
嵌入式 JSON de/serializer 不适用于类型。您可以使用不同的序列化库来解决此问题,但我会避免将其变成 "use [this] library".
本质上,JSON.parse
未能按预期解析对象。如果您完全删除参数并在问题中的 JSON 上尝试使用原始 JSON.parse(json);
,您将得到 role
,即 String
而不是 Role
,你可能会想到。 JSON.parse
没有进行任何类型转换,这意味着您有两个选择:使用库或使用您的方法。
不幸的是,如果您有嵌套对象,您的方法会变得复杂,但是随着类型的改变,您似乎剩下的唯一选择就是手动显式解析对象。
TL;DR:你的方法很好。