我正在研究自定义JsonSerializer和JsonDeserializer 我想将json(ints)序列化为枚举,并反序列化枚举为int
我为此创建了一个接口,其中枚举具有一个名为fromValue的函数,该函数应采用反序列化的值并返回枚举:
interface EnumSerializationInterface {
val value: Int
fun fromValue(value: Int): EnumSerializationInterface?
}
示例枚举:
enum class TestDummyEnumTestEnum(override val value: Int):
EnumSerializationInterface {
ENUM1(1),
ENUM2(2);
override fun fromValue(value: Int): EnumSerializationInterface? {
for (enum in TestDummyEnumTestEnum.values()) {
if (enum.value == value) {
return enum
}
}
return null
}
}
我的序列化器可以工作,但是反序列化,我的序列化器和反序列化器遇到问题:
class EnumDeserializer: JsonDeserializer<EnumSerializationInterface> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): EnumSerializationInterface {
val value = json.asInt()
return typeOfT.fromValue(value)
/*THIS DOES NOT WORK*/
}
}
class EnumSerializer: JsonSerializer<EnumSerializationInterface> {
override fun serialize(src: EnumSerializationInterface?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
return context!!.serialize(src!!.value)
}
}
我的问题是我无法从typeOfT获取'fromValue'函数。
有人知道如何获取实际的typeOfT吗?
答案 0 :(得分:0)
这是我的解决方案。我利用一个伴随对象来建立枚举查找。这使我的编码枚举要理解起来稍微复杂一些,但是声明枚举时的样板要少一些:
interface CodedEnum {
val code: Int
}
// It has to take class as parameter, since it is not possible to access T.values()
// This is Java generics limitation: https://stackoverflow.com/questions/2205891/iterate-enum-values-using-java-generics
open class CodedEnumLookup<E>(klass: Class<E>) where E: Enum<E>, E: CodedEnum {
val lookup = klass.enumConstants.associate { it.code to it }
init {
// Make sure no duplicate codes
check(lookup.size == klass.enumConstants.size)
}
fun get(code: Int): E {
return lookup[code]!!
}
}
用法示例:
enum class Color(override val code: Int): CodedEnum {
RED(0),
GREEN(1),
BLUE(2);
companion object: CodedEnumLookup<Color>(Color::class.java)
}
在Gson中,使用了Kotlin的反射的一些用法:
object CodedEnumSerializer : JsonSerializer<CodedEnum>, JsonDeserializer<CodedEnum> {
override fun serialize(src: CodedEnum, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
return JsonPrimitive(src.code)
}
// Not sure about how performant this solution is
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): CodedEnum {
return ((typeOfT as Class<*>).kotlin.companionObjectInstance as CodedEnumLookup<*>).get(json.asInt) as CodedEnum
}
}
GsonBuilder().registerTypeHierarchyAdapter(CodedEnum::class.java, CodedEnumSerializer)