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