Untitled

mail@pastecode.io avatar
unknown
kotlin
2 years ago
1.7 kB
1
Indexable
Never
@Retention(RUNTIME)
annotation class FallbackEnum

interface EnumJsonNameProvider {
    val jsonName: String
}

class MoshiEnumAdapterFactory : JsonAdapter.Factory {

    override fun create(
        type: Type,
        annotations: Set<Annotation>,
        moshi: Moshi,
    ): JsonAdapter<*>? {
        val rawType = Types.getRawType(type)
        if (rawType.interfaces.contains(FallbackEnum::class.java)) {
            @Suppress("UNCHECKED_CAST")
            val enumType = rawType as Class<Enum<*>>

            @Suppress("UNCHECKED_CAST")
            val enumConstants = enumType.enumConstants as Array<Enum<*>>
            val fallbackEnum = enumConstants.find {
                enumType.getField(it.name).getAnnotation(FallbackEnum::class.java) != null
            }
            if (EnumJsonNameProvider::class.java in rawType.interfaces) {
                return EnumJsonAdapterByProvider(enumConstants, fallbackEnum)
            }
            return EnumJsonAdapter.create(enumType).withUnknownFallback(fallbackEnum).nonNull()
        }
        return null
    }

    private class EnumJsonAdapterByProvider<T : Enum<T>>(
        enumConstants: Array<T>,
        private val fallbackEnum: T?,
    ) : JsonAdapter<T>() {
        @Suppress("UNCHECKED_CAST")
        private val enumConstants = enumConstants as Array<EnumJsonNameProvider>

        override fun fromJson(reader: JsonReader): T? {
            val value = reader.nextString()
            @Suppress("UNCHECKED_CAST")
            return enumConstants.find { it.jsonName == value } as? T ?: fallbackEnum
        }

        override fun toJson(writer: JsonWriter, value: T?) {
            writer.value((value as? EnumJsonNameProvider)?.jsonName)
        }
    }
}