【发布时间】:2019-01-21 02:41:49
【问题描述】:
我正在尝试构建一个通用类来处理 Kotlin 和 Java 中的配置注入。
基本上,我希望一个类绑定到一个数据类和一个资源文件的路径,该文件应该包含数据类实例的可轻松写入的反序列化。
到目前为止,我想出的是:
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
class ResourceLoader()
inline fun <reified T : Any> loadObject(resourcePath: String): T {
// Load resource file
val resource = ResourceLoader::class.java.classLoader.getResource(resourcePath)
val resourceContent = resource.readText()
// Return deserialized object
return jacksonObjectMapper().readValue(resourceContent)
}
abstract class ResourceBound<T : Any>(val resourcePath: String) {
inline fun <reified U : T> getResource(): U {
return loadObject(this.resourcePath)
}
}
有了这个,我可以将一个测试类绑定到一个资源文件的存在,如果文件缺少格式错误,它会在光荣的异常中失败,如下所示:
data class ServiceConfig(val endpoint: String, val apiKey: String)
class TestClassLoadingConfig() : ResourceBound<ServiceConfig>("TestConfig.json") {
@Test
fun testThis() {
val config: ServiceConfig = this.getResource()
val client = ServiceClient(config.endpoint, config.apiKey)
...
}
}
唯一的问题是它只适用于 Kotlin,因为 inline 与 java 不兼容。那么我该如何解决呢?
作为奖励,我想摆脱显式类型声明,所以 val config: ServiceConfig = this.getResource() 可以只是 val config = this.getResource()。
【问题讨论】:
-
您可以改用未经检查的演员表,例如只是写
return jacksonObjectMapper().readValue(resourceContent) as T。 -
如果我使用 Kotlin 化的
jacksonObjectMapper(),我会得到Cannot use 'T' as reified type parameter. Use a class instead.。如果我改为尝试ObjectMapper().readValue(resource, object : TypeReference<T>() {}) as T,则会出现运行时异常:java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to dk.whatever... -
抱歉,我的错误...在取消/编组时,您需要一个具体的类型...这也是您使用
TypeReference<T>() {}提供的...至少我是这么认为的...如果你只是传递类型本身(例如dk.whatever.....class),那么它可以工作吗? -
不。我现在正在尝试用 Java 编写代码,我会看看它是否可以在 Kotlin 中工作。
-
这看起来越来越像杰克逊的限制。我的 Java 实现也导致
ClassCastException
标签: java generics kotlin jackson jackson-databind