Skip to content

Commit

Permalink
TypeToken is now an interface.
Browse files Browse the repository at this point in the history
R8 fix.
  • Loading branch information
SalomonBrys authored and Romain Boisselle committed May 21, 2021
1 parent bb28a09 commit c7b511b
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection

internal class NativeKTypeTypeToken<T>(private val type: KType) : TypeToken<T>() {
internal class NativeKTypeTypeToken<T>(private val type: KType) : AbstractTypeToken<T>() {

override fun simpleDispString() = type.dispString(KClass<*>::simpleName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.kodein.type

import kotlin.reflect.KClass

internal abstract class AbstractKClassTypeToken<T>(protected val type: KClass<*>): TypeToken<T>() {
internal abstract class AbstractKClassTypeToken<T>(protected val type: KClass<*>): AbstractTypeToken<T>() {

override fun simpleDispString(): String = simpleErasedDispString()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ package org.kodein.type
* @property main The main type represented by this type token.
* @property params The type parameters of the main type.
*/
internal class CompositeTypeToken<T>(val main: TypeToken<T>, vararg val params: TypeToken<*>) : TypeToken<T>() {
internal class CompositeTypeToken<T>(val main: TypeToken<T>, vararg val params: TypeToken<*>) : AbstractTypeToken<T>() {

init {
if (params.isEmpty())
Expand Down
45 changes: 29 additions & 16 deletions kodein-type/src/commonMain/kotlin/org/kodein/type/TypeToken.kt
Original file line number Diff line number Diff line change
@@ -1,47 +1,42 @@
package org.kodein.type

/**
* An interface that contains a simple Type but is parameterized to enable type safety.
*
* @param T The type represented by this object.
*/
public abstract class TypeToken<T> {

public interface TypeToken<T> {
/**
* @return The simple (a.k.a. not fully qualified) name of the type represented by this TypeToken.
*/
public abstract fun simpleDispString(): String
public fun simpleDispString(): String

/**
* @return The simple (a.k.a. not fully qualified) erased (a.k.a without generic parameters) name of the type represented by this TypeToken.
*/
public abstract fun simpleErasedDispString(): String
public fun simpleErasedDispString(): String

/**
* @return The fully qualified name of the type represented by this TypeToken.
*/
public abstract fun qualifiedDispString(): String
public fun qualifiedDispString(): String

/**
* @return The fully qualified erased (a.k.a without generic parameters) name of the type represented by this TypeToken.
*/
public abstract fun qualifiedErasedDispString(): String
public fun qualifiedErasedDispString(): String

/**
* @return the raw type represented by this type.
* If this type is not generic, than it's raw type is itself.
*/
public abstract fun getRaw(): TypeToken<T>
public fun getRaw(): TypeToken<T>

/**
* @return Whether the type represented by this TypeToken is generic.
*/
public abstract fun isGeneric(): Boolean
public fun isGeneric(): Boolean

/**
* @return A list of generic parameters (empty if this types does not have generic parameters).
*/
public abstract fun getGenericParameters(): Array<TypeToken<*>>
public fun getGenericParameters(): Array<TypeToken<*>>

/**
* Returns whether the type represented by this TypeToken is generic and is entirely wildcard.
Expand All @@ -57,17 +52,35 @@ public abstract class TypeToken<T> {
*
* @return Whether the type represented by this TypeToken is generic and is entirely wildcard, otherwise null.
*/
public abstract fun isWildcard(): Boolean
public fun isWildcard(): Boolean

/**
* Returns the parent type of the type represented by this TypeToken, if any.
*/
public abstract fun getSuper(): List<TypeToken<*>>
public fun getSuper(): List<TypeToken<*>>

/**
* Determines if the type represented by this type object is either the same as, or is a superclass or superinterface of, the type represented by the specified type parameter.
*/
public fun isAssignableFrom(typeToken: TypeToken<*>): Boolean

public companion object {
public val Unit: TypeToken<Unit> = erased<Unit>()
public val Any: TypeToken<Any> = erased<Any>()
}
}

/**
* An interface that contains a simple Type but is parameterized to enable type safety.
*
* @param T The type represented by this object.
*/
public abstract class AbstractTypeToken<T> : TypeToken<T> {

/**
* Determines if the type represented by this type object is either the same as, or is a superclass or superinterface of, the type represented by the specified type parameter.
*/
public open fun isAssignableFrom(typeToken: TypeToken<*>): Boolean {
public override fun isAssignableFrom(typeToken: TypeToken<*>): Boolean {
if (this == typeToken || this == Any)
return true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection

internal class JSKTypeTypeToken<T>(private val type: KType) : TypeToken<T>() {
internal class JSKTypeTypeToken<T>(private val type: KType) : AbstractTypeToken<T>() {

override fun simpleDispString() = type.toString()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ package org.kodein.type

import java.lang.reflect.*

internal abstract class JVMAbstractTypeToken<T> : TypeToken<T>() {

abstract val jvmType: Type
public interface JVMTypeToken<T> : TypeToken<T> {
public val jvmType: Type
}

internal abstract class JVMAbstractTypeToken<T> : AbstractTypeToken<T>(), JVMTypeToken<T> {

override fun simpleDispString() = jvmType.simpleDispString()
override fun qualifiedDispString() = jvmType.qualifiedDispString()

final override fun typeEquals(other: TypeToken<*>): Boolean {
require(other is JVMAbstractTypeToken<*>)
require(other is JVMTypeToken<*>)

return Equals(jvmType, other.jvmType)
}
Expand Down
2 changes: 1 addition & 1 deletion kodein-type/src/jvmMain/kotlin/org/kodein/type/JVMUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.lang.reflect.*
*/
public val TypeToken<*>.jvmType: Type get() =
when (this) {
is JVMAbstractTypeToken -> jvmType
is JVMTypeToken -> jvmType
else -> throw IllegalStateException("${javaClass.simpleName} is not a JVM Type Token")
}

Expand Down
12 changes: 10 additions & 2 deletions kodein-type/src/jvmMain/kotlin/org/kodein/type/typeTokensJVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,22 @@ internal abstract class TypeReference<T> {
val superType: Type = (javaClass.genericSuperclass as? ParameterizedType ?: throw RuntimeException("Invalid TypeToken; must specify type parameters")).actualTypeArguments[0]
}

@PublishedApi
internal class GenericJVMTypeTokenDelegate<T: Any>(private val typeToken: JVMTypeToken<T>, private val raw: Class<T>) : JVMTypeToken<T> by typeToken {
override fun getRaw(): TypeToken<T> = JVMClassTypeToken(raw)
override fun equals(other: Any?): Boolean = typeToken.equals(other)
override fun hashCode(): Int = typeToken.hashCode()
override fun toString(): String = typeToken.toString()
}

/**
* Function used to get a generic type at runtime.
*
* @param T The type to get.
* @return The type object representing `T`.
*/
@Suppress("UNCHECKED_CAST")
public actual inline fun <reified T : Any> generic(): TypeToken<T> = typeToken((object : TypeReference<T>() {}).superType) as TypeToken<T>
public actual inline fun <reified T : Any> generic(): TypeToken<T> = GenericJVMTypeTokenDelegate(typeToken((object : TypeReference<T>() {}).superType) as JVMTypeToken<T>, T::class.java)

private val Type.isReified: Boolean get() =
when (this) {
Expand All @@ -87,7 +95,7 @@ private val Type.isReified: Boolean get() =
/**
* Gives a [TypeToken] representing the given type.
*/
public fun typeToken(type: Type): TypeToken<*> =
public fun typeToken(type: Type): JVMTypeToken<*> =
when (val k = type.kodein()) {
is Class<*> -> JVMClassTypeToken(k)
is ParameterizedType -> JVMParameterizedTypeToken<Any>(k.also { require(it.isReified) { "Cannot create TypeToken for non fully reified type $k" } })
Expand Down

0 comments on commit c7b511b

Please sign in to comment.