我已经创建了一个 Kotlin 等价于 TypeReference<T>
像这样:
abstract class TypeReference<T> : Comparable<T> {
val type: Type get() = getGenericType()
val arguments: List<Type> get() = getTypeArguments()
final override fun compareTo(other: T): Int {
return 0
}
private fun getGenericType(): Type {
val superClass = javaClass.genericSuperclass
check(superClass !is Class<*>) {
"TypeReference constructed without actual type information."
}
return (superClass as ParameterizedType).actualTypeArguments[0]
}
private fun getTypeArguments(): List<Type> {
val type = getGenericType()
return if (type is ParameterizedType) {
type.actualTypeArguments.toList()
} else emptyList()
}
}
为了获得泛型类型的 Class<*>
及其参数,我还创建了以下扩展函数(我认为这是问题所在,因为这是堆栈跟踪失败的地方)。
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
else -> Class.forName(typeName)
}
我正在像这样进行单元测试:
@Test
fun `TypeReference should correctly identify the List of BigDecimal type`() {
// Arrange
val expected = List::class.java
val expectedParameter1 = BigDecimal::class.java
val typeReference = object : TypeReference<List<BigDecimal>>() {}
// Act
val actual = typeReference.type.toClass()
val actualParameter1 = typeReference.arguments[0].toClass()
// Assert
assertEquals(expected, actual)
assertEquals(expectedParameter1, actualParameter1)
}
我认为问题在于它抛出的扩展函数 else -> Class.forName(typeName)
:
java.lang.ClassNotFoundException: ?扩展 java.math.BigDecimal
是否有更好的方法来获取 Class<*>
的 Type
,即使它们是泛型类型参数?
答案 0 :(得分:2)
您需要在 is WildcardType -> ...
表达式中添加 when
分支以处理 ? extends java.math.BigDecimal
(Kotlin 等效为 out java.math.BigDecimal
)、?
(Kotlin 等效是 *
), ? super Integer
(Kotlin 等价物是 in java.math.Integer
):
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
is WildcardType -> upperBounds.singleOrNull()?.toClass() ?: Any::class.java
else -> Class.forName(typeName)
}
请注意,在此实现中,单个上限类型将解析为其上限,但所有其他 wildcard types(包括多个上限类型)将解析为 Class<Object>
答案 1 :(得分:-1)
https://github.com/pluses/ktypes
val typeReference = object : TypeReference<List<BigDecimal>>() {}
val superType = typeReference::class.createType().findSuperType(TypeReference::class)!!
println(superType.arguments.first())// List<java.math.BigDecimal>
println(superType.arguments.first().type?.arguments?.first())// java.math.BigDecimal