Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 科特林。尝试使用具体化类型来解析列表和数组_Kotlin_Kotlin Reified Type Parameters - Fatal编程技术网

Kotlin 科特林。尝试使用具体化类型来解析列表和数组

Kotlin 科特林。尝试使用具体化类型来解析列表和数组,kotlin,kotlin-reified-type-parameters,Kotlin,Kotlin Reified Type Parameters,我试图在解析json时使用具体化类型。 它可以完美地处理单个json条目,但无法处理list 问题: String.parseList()方法中缺少什么 为什么ClassCastException会出现在.first()上,尽管赋值在前面通过了一行 包质量保证 导入com.fasterxml.jackson.databind.ObjectMapper 导入org.slf4j.LoggerFactory 导入org.testng.Assert 导入org.testng.annotations.Te

我试图在解析json时使用具体化类型。 它可以完美地处理单个json条目,但无法处理list

问题:

  • String.parseList()方法中缺少什么
  • 为什么ClassCastException会出现在.first()上,尽管赋值在前面通过了一行
  • 包质量保证
    导入com.fasterxml.jackson.databind.ObjectMapper
    导入org.slf4j.LoggerFactory
    导入org.testng.Assert
    导入org.testng.annotations.Test
    类ReifiedParseListTest{
    数据类用户(变量名称:String=“userName”,变量年龄:Int=0)
    val log=LoggerFactory.getLogger(this.javaClass.name)
    val objectMapper=objectMapper()
    val json:String=“[{”name:“Alice”,“age:1},{”name:“Bob”,“age:2}]”
    val应为:String=“[User(name=Alice,age=1),User(name=Bob,age=2)]”
    inline fun String.parseList():List=objectMapper
    .readValue(这个数组::class.java).toList()
    @试验
    有趣的检查列表_OK(){
    val实际值:List=objectMapper
    .readValue(json,数组::class.java).toList()
    log.info(“actual.first()的类型为:{}”,actual.first().javaClass)
    Assert.assertEquals(实际的.toString(),应为)
    }
    @试验
    fun checkParseListReified_失败(){
    val实际值:List=json.parseList()
    Assert.assertEquals(实际的.toString(),应为)
    //java.lang.AssertionError:
    //预期:[用户(姓名=Alice,年龄=1),用户(姓名=Bob,年龄=2)]
    //实际值:[{name=Alice,age=1},{name=Bob,age=2}]
    }
    @试验
    fun checkParseListReifiedClassCast_失败(){
    val实际值:List=json.parseList()
    log.info(“actual.first()的类型为:{}”,actual.first().javaClass)
    //java.lang.ClassCastException:java.util.LinkedHashMap不能强制转换为qa.ReifiedParseListTest$User
    }
    }
    
    在这种情况下,
    具体化
    有助于传播类型的类,但仍然存在类型擦除。
    为了避免这种情况,您可以使用类似于
    JavaType

    inline fun <reified V> String.parseList(): List<V> {
        return objectMapper.readValue(this, objectMapper.getTypeFactory()
            .constructCollectionType(List::class.java, V::class.java))
    }
    
    您会注意到它返回
    数组,这是Kotlin说“这是来自Java的东西,我希望它能工作,但我不能保证”。现在,通过调用
    toList()
    这会放松编译器,说“是的,最后我们返回一个Kotlin类型,它会好起来的”。但实际上,这是一个虚假的承诺


    你得到的是
    Array
    中填充了
    LinkedHashMap
    ,当它们被转换到
    用户时,当然会失败,因为我们给了编译器一个错误的承诺。

    它失败是因为
    Array::class.java
    总是返回
    Array的类:

    inline fun String.parseList():List=objectMapper
    
    .readValue(这是Class.forName(“[L${V::Class.java.name};””)作为类。

    我最终得到了另一个解决方案,它似乎同时处理单个实体和列表

        inline fun <reified V> String.parse(): V = objectMapper.readValue(this, object : TypeReference<V>() {})
    
    @Test
    fun checkParseSingle() {
        val jsonSingle: String = """{"name":"Carol","age":3}"""
        val expectedSingle: String = "User(name=Carol, age=3)"
    
        val actual: User = jsonSingle.parse<User>()
        Assert.assertEquals(actual.toString(), expectedSingle)
    }
    
    @Test
    fun checkParseList() {
        val jsonList: String = """[{"name":"Alice","age":1},{"name":"Bob","age":2}]"""
        val expectedList: String = "[User(name=Alice, age=1), User(name=Bob, age=2)]"
    
        val actual: List<User> = jsonList.parse<List<User>>()
        Assert.assertEquals(actual.toString(), expectedList)
    }
    
    inline fun String.parse():V=objectMapper.readValue(此对象:TypeReference(){})
    @试验
    有趣的checkParseSingle(){
    val jsonSingle:String=“{”name:“Carol”,“age”:3}”“”
    val expectedSingle:String=“User(name=Carol,age=3)”
    val实际值:User=jsonSingle.parse()
    Assert.assertEquals(实际的.toString(),expectedSingle)
    }
    @试验
    有趣的检查列表(){
    val jsonList:String=“”[{“name”:“Alice”,“age:1},{“name”:“Bob”,“age:2}]”
    val expectedList:String=“[User(name=Alice,age=1),User(name=Bob,age=2)]”
    val实际值:List=jsonList.parse()
    Assert.assertEquals(实际的.toString(),expectedList)
    }
    
    您需要捕获
    T:class.java
    不会给出的泛型类型。但以下内容适用于任何泛型类型

    inline fun <reified T> jacksonTypeRef(): TypeReference<T> = object: TypeReference<T>() {}
    
    inline fun <reified T : Any> String.parseJson(): T {
        return objectMapper.readValue(this, jacksonTypeRef<T>())
    }
    
    inlinejacksontyperef():TypeReference=object:TypeReference(){}
    内联fun String.parseJson():T{
    返回objectMapper.readValue(这是jacksonTypeRef())
    }
    
    这是Kotlin,所以在构造名称时,您可能应该使用Spring模板:
    Class.forName(“[L${V::Class.java.name};”)
    有趣的技巧。因此,我必须在静态类型语言中使用字符串连接来正确解析类型……请记住这一点。
    inline fun <reified V> String.parseList(): List<V> = objectMapper
                    .readValue(this, Class.forName("[L${V::class.java.name};") as Class<Array<V>>).toList()
    
        inline fun <reified V> String.parse(): V = objectMapper.readValue(this, object : TypeReference<V>() {})
    
    @Test
    fun checkParseSingle() {
        val jsonSingle: String = """{"name":"Carol","age":3}"""
        val expectedSingle: String = "User(name=Carol, age=3)"
    
        val actual: User = jsonSingle.parse<User>()
        Assert.assertEquals(actual.toString(), expectedSingle)
    }
    
    @Test
    fun checkParseList() {
        val jsonList: String = """[{"name":"Alice","age":1},{"name":"Bob","age":2}]"""
        val expectedList: String = "[User(name=Alice, age=1), User(name=Bob, age=2)]"
    
        val actual: List<User> = jsonList.parse<List<User>>()
        Assert.assertEquals(actual.toString(), expectedList)
    }
    
    inline fun <reified T> jacksonTypeRef(): TypeReference<T> = object: TypeReference<T>() {}
    
    inline fun <reified T : Any> String.parseJson(): T {
        return objectMapper.readValue(this, jacksonTypeRef<T>())
    }