Kotlin - TypeReference<T> 无法为类型参数获取 Class<*>

时间:2021-03-06 12:08:12

标签: kotlin

我已经创建了一个 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,即使它们是泛型类型参数?

2 个答案:

答案 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