代码之家  ›  专栏  ›  技术社区  ›  Matthew Layton

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

  •  0
  • Matthew Layton  · 技术社区  · 4 年前

    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) 当它抛出:

    属于 Type

    0 回复  |  直到 4 年前
        1
  •  2
  •   Михаил Нафталь    4 年前

    您需要添加 is WildcardType -> ... 分支到您的 when -表达式来处理以下类型 ? extends java.math.BigDecimal 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>

        2
  •  -1
  •   user15583155    4 年前

    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