我最近才开始尝试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>
但这似乎并没有改变任何东西。 有什么方法可以使它优雅地工作吗?
答案 0 :(得分:1)
由于在运行时不存在所有通用类型信息,因此您需要以某种方式将其提供给Jackson。修饰类型保留该信息,但是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