Kotlin Intersection Types(A & B)

I’m using Gson. I need to serialize and deserialize numbers and enumerations. So I need to have a factory class, which will create the actual “TypeAdapter”, as shown in the following code:

interface NumberEnum {
    val value: Int
}

class EnumAndNumberConverterFactory : TypeAdapterFactory {
    override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
        val rawType = type.rawType
        if (!rawType.isEnum || !NumberEnum::class.java.isAssignableFrom(rawType)) {
            return null
        }

        @Suppress("UNCHECKED_CAST")
        return EnumNumberTypeAdapter(rawType/* Type Error */).nullSafe() as TypeAdapter<T>
    }
}

class EnumNumberTypeAdapter<T>(private val clazz: Class<T>) : TypeAdapter<T>()
        where T : NumberEnum, T : Enum<T> {

    private val cache = clazz.enumConstants!!.associateBy { it.value }

    override fun write(out: JsonWriter, value: T) {
        out.value(value.value)
    }

    override fun read(`in`: JsonReader): T {
        val value = `in`.nextInt()
        return cache[value]
            ?: throw IllegalArgumentException("Unknown enum value [$value] for enum class [${clazz.simpleName}]")
    }
}

But even though I did type judgment, the Kotlin compiler still didn’t think my input parameters were legal. My solution now is to cheat the Kotlin compiler by defining an empty enum class, implementing the NumberEnum interface, and then letting “rawType” as it:

enum class CheatUnionType : NumberEnum
...
return EnumNumberTypeAdapter(rawType as Class<CheatUnionType>).nullSafe() as TypeAdapter<T>
...

Is there a better way to solve this problem? Typealias does not seem to solve this problem

Maybe there is a better way, but we can introduce a function which doesn’t do anything but helps us type the variable according to our needs:

@Suppress("UNCHECKED_CAST")
fun <R, S> cast(c: Class<S>): Class<R> where R : NumberEnum, R : Enum<S> = c as Class<R>

@Suppress("UNCHECKED_CAST")
return EnumNumberTypeAdapter(cast(rawType)).nullSafe() as TypeAdapter<T>

But I’m not sure it is generally a good idea to design our code around intersection types in the language which doesn’t really support them. Only because we can have a type parameter with multiple upper bounds, doesn’t yet mean we have intersection types. By pretending Kotlin have them, we may shoot ourselves in the foot, as in the example above.

Just in case, there is a large discussion about the future of intersection types: https://youtrack.jetbrains.com/issue/KT-13108/Denotable-union-and-intersection-types.