Kotlin-TypeReference T无法获得Class *对于类型参数 [英] Kotlin - TypeReference<T> Cannot obtain Class<*> For Type Arguments

查看:149
本文介绍了Kotlin-TypeReference T无法获得Class *对于类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了与 TypeReference< T> 等效的Kotlin,如下所示:

I've created a Kotlin equivalent of TypeReference<T> like so:

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< *> ,我还创建了以下扩展函数(这是我认为问题出在哪里,因为这是堆栈跟踪失败的地方.)

In order to obtain Class<*> of the generic type and its arguments, I've also created the following extension function (and this is where I believe the problem lies, since this is where the stack trace fails).

fun Type.toClass(): Class<*> = when (this) {
    is ParameterizedType -> rawType.toClass()
    is Class<*> -> this
    else -> Class.forName(typeName)
}

我正在像这样进行单元测试:

I'm unit testing this like so:

@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):

The problem I think, lies in the extension function else -> Class.forName(typeName) as it throws:

java.lang.ClassNotFoundException:吗?扩展java.math.BigDecimal

java.lang.ClassNotFoundException: ? extends java.math.BigDecimal

即使它们是通用类型参数,是否还有更好的方法来获取 Type Class< *> ?

Is there a better way to obtain the Class<*> of a Type, even when they're generic type parameters?

推荐答案

您需要添加 is WildcardType->... 分支到您的何时表达式来处理类似的类型?扩展java.math.BigDecimal (Kotlin等效于 out java.math.BigDecimal ),?(Kotlin等效于 * ),?超级整数(Kotlin等效于java.math.Integer 中的):

You need to add is WildcardType -> ... branch to your when-expression to handle types like ? extends java.math.BigDecimal (Kotlin equivalent is out java.math.BigDecimal), ?(Kotlin equivalent is *), ? super Integer(Kotlin equivalent is 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)
}

请注意,在此实现中,单个上限类型将被解析为其上限,但所有其他通配符类型(包括多个上限类型)将解析为 Class< Object>

Note that in this implementation single upper bound types will be resolved as its upper bound, but all other wildcard types (including multiple upper bounds types) will be resolved as Class<Object>

这篇关于Kotlin-TypeReference T无法获得Class *对于类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆