如何将JSON反序列化为一个列表与Kotlin + Jackson [duplicate]

时间:2022-03-10 18:02:16

This question already has an answer here:

这个问题已经有了答案:

What is the correct syntax to deserialize the following JSON:

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

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

I tried:

我试着:

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

However I want:

但是我想:

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

The above syntax is not correct and gives: only classes are allowed on the left hand side of a class literal

上面的语法是不正确的,并给出:只允许类在类文字的左边

3 个解决方案

#1


17  

NOTE: The answer from @IRus is also correct, it was being modified at the same time I wrote this to fill in more details.

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

You should use the Jackson + Kotlin module or you will have other problems deserializing into Kotlin objects when you do no have a default constructor.

您应该使用Jackson + Kotlin模块,否则在没有默认构造函数的情况下,在Kotlin对象中反序列化会遇到其他问题。

Your first sample of the code:

您的第一个示例代码:

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

Is returning an inferred type of List<*> since you did not specify more type information, and it is actually a List<Map<String,Any>> which is not really "working OK" but is not producing any errors. It is unsafe, not typed.

返回一个推断类型的列表<*>,因为您没有指定更多的类型信息,它实际上是一个列表 >都不是“正常工作”,但不会产生任何错误。它是不安全的,不是打印出来的。

The second code should be:

第二项守则应是:

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

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

You do not need anything else on the right side of the assignment, the Kotlin module for Jackson will reify the generics and create the TypeReference for Jackson internally. Notice the readValue import, you need that or .* for the com.fasterxml.jackson.module.kotlin package to have the extension functions that do all of the magic.

你不需要在任务的右边做任何其他的事情,Kotlin模块为杰克逊将使泛型具体化并在内部为杰克逊创建TypeReference。注意readValue导入,您需要将or .*用于com.fasterxml.jackson.module。kotlin包具有所有神奇功能的扩展函数。

A slightly different alternative that also works:

另一种稍微不同的方法也适用:

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

There is no reason to NOT use the extension functions and the add-on module for Jackson. It is small and solves other issues that would require you to jump through hoops to make a default constructor, or use a bunch of annotations. With the module, your class can be normal Kotlin (optional to be data class):

没有理由不为Jackson使用扩展函数和附加模块。它很小,并且可以解决其他问题,这些问题需要您跳过一些步骤来创建默认的构造函数,或者使用大量的注解。使用该模块,您的类可以是普通的Kotlin(可选为数据类):

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

#2


4  

Following code works well for me:

下面的代码很适合我:

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)
    }
}

This work because of extension function defined inside jackson-kotlin-module (that used reified generics):

这个工作是因为在jackson- kotlins模块中定义的扩展函数(使用了具体化的泛型):

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

Thanks @JaysonMinard for notify me about it.

谢谢jaysonminard告诉我。

Output:

输出:

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

#3


4  

The error you're getting is about following expression:

您得到的错误是以下表达式:

List<GenreDTO>::class.java

Because of how jvm treats generics there's no separate class for List<GenreDTO> thus compiler complains. Similarly in Java the following will not compile:

由于jvm处理泛型的方式,所以List 没有单独的类,因此编译器会抱怨。类似地,在Java中,以下代码不会编译:

List<GenreDTO>.getClass()

Here's a sample that will deserialize the list properly:

下面是一个将列表反序列化的示例:

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

As @JaysonMinard has pointed out you can use jackson-module-kotlin to simplify the invocation to:

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

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

This is possible because of reified type parameters. Consider looking at Extensions to find out details.

这是可能的,因为具体化类型参数。考虑查看扩展以找到细节。

#1


17  

NOTE: The answer from @IRus is also correct, it was being modified at the same time I wrote this to fill in more details.

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

You should use the Jackson + Kotlin module or you will have other problems deserializing into Kotlin objects when you do no have a default constructor.

您应该使用Jackson + Kotlin模块,否则在没有默认构造函数的情况下,在Kotlin对象中反序列化会遇到其他问题。

Your first sample of the code:

您的第一个示例代码:

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

Is returning an inferred type of List<*> since you did not specify more type information, and it is actually a List<Map<String,Any>> which is not really "working OK" but is not producing any errors. It is unsafe, not typed.

返回一个推断类型的列表<*>,因为您没有指定更多的类型信息,它实际上是一个列表 >都不是“正常工作”,但不会产生任何错误。它是不安全的,不是打印出来的。

The second code should be:

第二项守则应是:

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

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

You do not need anything else on the right side of the assignment, the Kotlin module for Jackson will reify the generics and create the TypeReference for Jackson internally. Notice the readValue import, you need that or .* for the com.fasterxml.jackson.module.kotlin package to have the extension functions that do all of the magic.

你不需要在任务的右边做任何其他的事情,Kotlin模块为杰克逊将使泛型具体化并在内部为杰克逊创建TypeReference。注意readValue导入,您需要将or .*用于com.fasterxml.jackson.module。kotlin包具有所有神奇功能的扩展函数。

A slightly different alternative that also works:

另一种稍微不同的方法也适用:

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

There is no reason to NOT use the extension functions and the add-on module for Jackson. It is small and solves other issues that would require you to jump through hoops to make a default constructor, or use a bunch of annotations. With the module, your class can be normal Kotlin (optional to be data class):

没有理由不为Jackson使用扩展函数和附加模块。它很小,并且可以解决其他问题,这些问题需要您跳过一些步骤来创建默认的构造函数,或者使用大量的注解。使用该模块,您的类可以是普通的Kotlin(可选为数据类):

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

#2


4  

Following code works well for me:

下面的代码很适合我:

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)
    }
}

This work because of extension function defined inside jackson-kotlin-module (that used reified generics):

这个工作是因为在jackson- kotlins模块中定义的扩展函数(使用了具体化的泛型):

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

Thanks @JaysonMinard for notify me about it.

谢谢jaysonminard告诉我。

Output:

输出:

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

#3


4  

The error you're getting is about following expression:

您得到的错误是以下表达式:

List<GenreDTO>::class.java

Because of how jvm treats generics there's no separate class for List<GenreDTO> thus compiler complains. Similarly in Java the following will not compile:

由于jvm处理泛型的方式,所以List 没有单独的类,因此编译器会抱怨。类似地,在Java中,以下代码不会编译:

List<GenreDTO>.getClass()

Here's a sample that will deserialize the list properly:

下面是一个将列表反序列化的示例:

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

As @JaysonMinard has pointed out you can use jackson-module-kotlin to simplify the invocation to:

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

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

This is possible because of reified type parameters. Consider looking at Extensions to find out details.

这是可能的,因为具体化类型参数。考虑查看扩展以找到细节。