从Redis反序列化泛型列表时返回LinkedHashMap问题排查
问题描述
我有如下一段Kotlin代码:
val objs = results.map { if(it == null) return@map null val typeRef: TypeReference<T> = object : TypeReference<T>() {} jacksonObjectMapper().readValue(it, typeRef) }
我希望该方法返回泛型类型T的可空列表List<T?>,其中T是方法签名中的泛型参数。虽然代码能运行,但未达到预期效果:当调用myMethod<MyDTO>(keys: List<String>)时,返回的是LinkedHashMap列表而非预期的MyDTO列表。请问我哪里出错了?
问题原因
这是泛型类型擦除导致的问题。JVM运行时会抹掉泛型参数T的具体类型信息,你创建的TypeReference<T>其实根本不知道T是MyDTO,Jackson没法把数据反序列化成MyDTO对象,只能默认用LinkedHashMap存储JSON的键值对。
解决方案
1. 让方法接收TypeReference<T>作为参数
直接让调用方传入包含具体类型信息的TypeReference,这样Jackson就能明确知道要转成什么类型:
fun <T> myMethod(keys: List<String>, typeRef: TypeReference<T>): List<T?> { val results = // 这里写获取原始数据的逻辑 return results.map { if (it == null) null else jacksonObjectMapper().readValue(it, typeRef) } } // 调用示例 val result = myMethod(listOf("key1"), object : TypeReference<MyDTO>() {})
2. 用KClass结合TypeFactory生成类型信息
如果不想让调用方传TypeReference,可以用Kotlin的KClass来构建准确的类型信息:
fun <T : Any> myMethod(keys: List<String>, clazz: KClass<T>): List<T?> { val results = // 这里写获取原始数据的逻辑 val targetType = jacksonObjectMapper().typeFactory.constructType(clazz.java) return results.map { if (it == null) null else jacksonObjectMapper().readValue(it, targetType) } } // 调用示例 val result = myMethod(listOf("key1"), MyDTO::class)
3. 利用reified泛型(仅限inline函数)
如果方法可以定义为inline函数,用reified关键字就能保留泛型的具体类型信息,不用额外传参数:
inline fun <reified T : Any> myMethod(keys: List<String>): List<T?> { val results = // 这里写获取原始数据的逻辑 return results.map { if (it == null) null else jacksonObjectMapper().readValue(it, object : TypeReference<T>() {}) } } // 调用示例 val result = myMethod<MyDTO>(listOf("key1"))
这里因为reified保留了T的具体类型,TypeReference<T>能正确识别出MyDTO,Jackson就能正常完成反序列化。
内容的提问来源于stack exchange,提问作者Matias Barrios
相关产品推荐
相关产品推荐

