如何在带有枚举的kotlinjs中正确使用JSON.parse?

gei*_*aos 0 enums parsing json kotlin kotlin-js

在使用Kotlin-react进行新的冒险期间,尝试解析来自包含枚举值的后端数据时,我遇到了困难。
Spring-Boot以JSON形式发送对象,如下所示:

{
  "id": 1,
  "username": "Johnny",
  "role": "CLIENT"
}
Run Code Online (Sandbox Code Playgroud)

role在这种情况下是枚举值,可以有两个值CLIENTLECTURER。如果我要使用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
}
Run Code Online (Sandbox Code Playgroud)

在其中,我必须手动定义从字符串值到枚举的转换。

我缺少一些可以简化此行为的东西吗?

(我不是指对JSON使用id并查找ID,等等。我对Kotlin-JS中的某些方法感到好奇)

我有一个假设,那就是因为JSON.parseJS中的“原始”代码不会这样做,而且Kotlin不会在其中添加任何其他内容,但我仍然有希望!

Zoe*_*Zoe 5

据我所知,没有。

问题

当使用嵌入式JSON类进行反序列化时,Kotlin.JS会产生令人难以置信的怪异类型,这实际上是JavaScript JSON类镜像。尽管我还没有做很多JavaScript,但是它的类型处理几乎不存在。只有手动抛出可以强制执行它,因此JSON.parse不在乎它是否返回SomeCustomObject具有完全相同字段的或新创建的对象。

举个例子,如果您有两个具有相同字段名的类(没有继承),并且有一个接受变量的函数,那么它不会在意其中接收哪一个(或第三个)只要它尝试访问该类的变量存在。

类型问题在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}");
    }
}
Run Code Online (Sandbox Code Playgroud)

您希望该打印什么?自然会期望得到一个Struct。该类型也被明确声明

不幸的是,事实并非如此。而是打印:

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}");
    }
}
Run Code Online (Sandbox Code Playgroud)

重点

嵌入式JSON de / serializer不适用于类型。您也许可以通过使用其他序列化库来解决此问题,但是我将避免将其变成“使用[this]库”。

本质上,JSON.parse无法按预期解析对象。如果您完全删除参数并尝试JSON.parse(json);对问题中的JSON进行原始处理role,则可能会得到a String而不是a Role。而且由于JSON.parse不进行类型转换,这意味着您有两个选择:使用库或使用方法。

不幸的是,如果您有嵌套的对象,您的方法将变得复杂,但是随着类型的改变,您剩下的唯一选择就是显式地手动解析对象。

TL; DR:您的方法很好。