如何使用Kotlin + Jackson将JSON反序列化为List <sometype>

时间:2016-01-11 08:08:09

标签: json jackson kotlin

反序列化以下JSON的正确语法是什么:

[ {
  "id" : "1",
  "name" : "Blues"
}, {
  "id" : "0",
  "name" : "Rock"
} ]

我试过了:

//Works OK
val dtos  = mapper.readValue(json, List::class.java)

但是我想:

val dtos : List<GenreDTO>  = mapper.readValue(json, 
    List<GenreDTO>::class.java)

上述语法不正确,并提供:only classes are allowed on the left hand side of a class literal

3 个答案:

答案 0 :(得分:22)

注意: @IRus的答案也是正确的,在我写这篇文章的同时修改了它以填写更多细节。

您应该使用Jackson + Kotlin module,否则当您没有默认构造函数时,您将遇到其他问题反序列化为Kotlin对象。

您的第一个代码示例:

val dtos  = mapper.readValue(json, List::class.java)

返回推断类型的List<*>,因为你没有指定更多的类型信息,实际上它是List<Map<String,Any>>并不是真的&#34;工作正常&#34;但不会产生任何错误。这是不安全的,不是打字的。

第二个代码应为:

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue

val mapper = jacksonObjectMapper()
// ...
val genres: List<GenreDTO> = mapper.readValue(json)

在作业的右侧你不需要任何其他内容,杰克逊的Kotlin模块将重新设计泛型,并在内部为杰克逊创建TypeReference。请注意readValue导入,您需要.* com.fasterxml.jackson.module.kotlin包含val genres = mapper.readValue<List<GenreDTO>>(json) 包,以获得完成所有魔法的扩展功能。

略有不同的替代方案也有效:

data

没有理由不使用Jackson的扩展功能和附加模块。它很小并且解决了其他需要你跳过箍来制作默认构造函数或者使用一堆注释的问题。使用该模块,您的类可以是普通的Kotlin(可选为class GenreDTO(val id: Int, val name: String) 类):

<asp:ListView ID="lstAllProducts" runat="server">
        <ItemTemplate>
            <a style="color: black" href="ProductInfo.aspx?id=<%# Eval("itemId") %>">
                <div class="wrpInnerItem hvr-fade">
                    <div class="innerItem">
                        <p><%#Eval("gtin")%></p>
                    </div>
                    <div class="innerItem">
                        <p><%#Eval("brandName")%></p>
                    </div>
                    <div class="innerItem">
                        <p><%#Eval("functionalName")%></p>
                    </div>
                    <div class="innerItem">
                        <p><%#Eval("unitDescription")%></p>
                    </div>
                    <div class="innerItem">
                        <p><%#Eval("articleNr")%></p>
                    </div>
                </div>
            </a>
        </ItemTemplate>
    </asp:ListView>

答案 1 :(得分:5)

以下代码适用于我:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule



val json = """[ {
  "id" : "1",
  "name" : "Blues"
}, {
  "id" : "0",
  "name" : "Rock"
} ]"""

data class GenreDTO(val id: Int, val name: String)

val mapper = ObjectMapper().registerKotlinModule()

fun main(args: Array<String>) {
    val obj: List<GenreDTO> = mapper.readValue(json)
    obj.forEach {
        println(it)
    }
}

这项工作是因为jackson-kotlin-module(使用reified泛型)中定义的扩展函数:

 public inline fun <reified T: Any> ObjectMapper.readValue(content: String): T = readValue(content, object: TypeReference<T>() {})

感谢@JaysonMinard通知我。

输出:

GenreDTO(id=1, name=Blues)
GenreDTO(id=0, name=Rock)

答案 2 :(得分:5)

您获得的错误是关于以下表达式:

List<GenreDTO>::class.java

由于jvm如何处理泛型,因此List<GenreDTO>没有单独的类,因此编译器会抱怨。同样在Java中,以下内容不会编译:

List<GenreDTO>.getClass()

这是一个可以正确反序列化列表的示例:

val value:List<GenreDTO> = mapper.readValue(json, object : TypeReference<List<GenreDTO>>() {})

正如@JaysonMinard指出的那样,你可以使用jackson-module-kotlin来简化调用:

val genres: List<GenreDTO> = mapper.readValue(json)
// or
val genres = mapper.readValue<List<GenreDTO>>(json)

由于reified type parameters,这是可能的。考虑查看Extensions以查找详细信息。