generics - 使用通用函数不适用于使用 jackson 加载 YAML 列表

标签 generics kotlin jackson yaml

我最近才开始尝试 Kotlin,到目前为止我对它感到非常惊讶。但是,我不能完全理解泛型在这里是如何工作的。

我想读取如下所示的 YAML 文件:

- id: acrobatics
  name: Akrobatik
  description:
  ...

一个简单的数据类将其映射到:
data class Skill (
    val id: String,
    val name: String,
    val description: String
)

现在,进入有趣的部分。 显然,它确实适用于泛型!
我从这个函数开始,它按预期完成了它的工作:
fun loadSkills(): List<Skill> {

    val resource: URL = classLoader.getResource("rulebook/skills.yml")!!

    val items: List<Skill> = resource.openStream()
        .bufferedReader().use() { reader ->
            objectMapper.readValue<List<Skill>>(reader)
        }

    return items
}

但是,我想重用它,所以我尝试创建一个通用函数:
protected fun <R: Any> loadList(path: String): List<R> {

    val resource: URL = classLoader.getResource(path)!!

    val items: List<R> = resource.openStream()
        .bufferedReader().use() { reader ->
            objectMapper.readValue<List<R>>(reader)
        }

    return items
}

我原来的函数只是调用:
return loadList<Skill>("rulebook/skills.yml")

现在我的测试失败了,因为我得到了一个 LinkedHashMaps 列表,这似乎是 YAML 解析器用来映射对象的默认数据类型。
我阅读了更多内容并尝试将我的方法签名更改为具有具体类型参数的内联函数:
protected inline fun <reified R: Any> loadList(path: String): List<R>

但这似乎并没有改变任何东西。
有什么办法可以优雅地完成这项工作吗?

最佳答案

由于在运行时不存在所有泛型类型信息,因此您需要以某种方式将其提供给 Jackson。 Reified type 保留该信息,但 AFAIK Jackson 不使用它,因此您必须手动执行。例如,像这样:

inline fun <reified T> loadSkills(path: String): List<T> {

    val resource: URL = javaClass.classLoader.getResource(path)
    val type = objectMapper.typeFactory.constructParametricType(List::class.java, T::class.java)
    val items: List<T> = resource.openStream()
                .bufferedReader().use { reader ->
                    objectMapper.readValue(reader, type)
                }

    return items
}

编辑 : 事实证明,jackson-kotlin-module 对嵌套泛型类型的自动计算存在限制。
如果您尝试为单个技能(没有列表)解析 yaml(或其他任何内容),即使在泛型函数中它也可以正常工作,但是一旦您想要像 List< Skill> 那样进行嵌套,它就无法正确识别类型并产生 List of哈希映射

关于generics - 使用通用函数不适用于使用 jackson 加载 YAML 列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56752508/

相关文章:

c++ - 通用 lambda 与标准模板函数(使用什么以及何时使用)

kotlin - Android 13如何处理不允许通知?如何解释允许的理由?

java - 需要有关创建通用数组的帮助

c# - 使用通用返回类型切换类型

c# - C# 中的泛型属性

c# - 如何将类型化值转换为通用类型 T?

android - FragmentPagerAdapter 已弃用

java - 如何更改 kotlin 中 viewpager 自动滑动的默认速度?

java - 使用 Spring 和 Jackson JSON 将 java.io.Serializable 实例序列化为 JSON

java - 如何在序列化期间忽略字段,但在反序列化期间不忽略?