来自JSON的Kotlin Jackson生成对象

Nat*_*ein 3 json jackson kotlin

请帮忙!我正在尝试使用jackson kotlin模块从JSON生成对象.这是json来源:

{
    "name": "row",
    "type": "layout",
    "subviews": [{
        "type": "horizontal",
        "subviews": [{
            "type": "image",
            "icon": "ic_no_photo",
            "styles": {
                "view": {
                    "gravity": "center"
                }
            }
        }, {
            "type": "vertical",
            "subviews": [{
                "type": "text",
                "fields": {
                    "text": "Some text 1"
                }
            }, {
                "type": "text",
                "fields": {
                    "text": "Some text 2"
                }
            }]
        }, {
            "type": "vertical",
            "subviews": [{
                "type": "text",
                "fields": {
                    "text": "Some text 3"
                }
            }, {
                "type": "text",
                "fields": {
                    "text": "Some text 4"
                }
            }]
        }, {
            "type": "vertical",
            "subviews": [{
                "type": "image",
                "icon": "ic_no_photo"
            }, {
                "type": "text",
                "fields": {
                    "text": "Some text 5"
                }
            }]
        }]
    }]
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试生成Skeleton类的实例.

data class Skeleton (val type : String,
                         val name: String,
                         val icon: String,
                         val fields: List<Field>,
                         val styles: Map<String, Map<String, Any>>,
                         val subviews : List<Skeleton>)

data class Field (val type: String, val value: Any)
Run Code Online (Sandbox Code Playgroud)

如您所见,Skeleton对象可以在其中包含其他Skeleton对象(并且这些对象也可以包含其他Skeleton对象),Skeleton也可以具有List of Field对象

val mapper = jacksonObjectMapper()
val skeleton: Skeleton = mapper.readValue(File(file))
Run Code Online (Sandbox Code Playgroud)

此代码以例外结束:

com.fasterxml.jackson.databind.JsonMappingException: Instantiation of [simple type, class com.uibuilder.controllers.parser.Skeleton] value failed (java.lang.IllegalArgumentException): Parameter specified as non-null is null: method com.uibuilder.controllers.parser.Skeleton.<init>, parameter name
 at [Source: docs\layout.txt; line: 14, column: 3] (through reference chain: com.uibuilder.controllers.parser.Skeleton["subviews"]->java.util.ArrayList[0]->com.uibuilder.controllers.parser.Skeleton["subviews"]->java.util.ArrayList[0])
Run Code Online (Sandbox Code Playgroud)

hot*_*key 6

我发现有几个关于映射的问题阻止了Jackson从JSON中读取值:

  • Skeletonclass具有非null构造函数参数(例如val type: String,不是String?),null如果JSON中缺少这些参数的值,Jackson会传递给它们.这就是导致您提到的异常的原因:

    指定为非null的com.uibuilder.controllers.parser.Skeleton.<init>参数为null:method ,parametername

    为避免这种情况,您应该将可能包含值的参数标记为可为空(您的案例中的所有参数):

    data class Skeleton(val type: String?,
                        val name: String?,
                        val icon: String?,
                        val fields: List<Field>?,
                        val styles: Map<String, Map<String, Any>>?,
                        val subviews : List<Skeleton>?)
    
    Run Code Online (Sandbox Code Playgroud)
  • fieldsin Skeletonhas type List<Field>,但在JSON中它由单个对象表示,而不是由数组表示.修复方法是将fields参数类型更改为Field?:

    data class Skeleton(...
                        val fields: Field?,
                        ...)
    
    Run Code Online (Sandbox Code Playgroud)
  • 此外,Field代码中的类与JSON中的对象不匹配:

    "fields": {
        "text": "Some text 1"
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您也应该更改Field类,以便它具有text属性:

    data class Field(val text: String)
    
    Run Code Online (Sandbox Code Playgroud)

在我列出的更改后,杰克逊可以成功阅读有问题的JSON.


另见: Kotlin参考文献中的"Null Safety".