Gson使用通用代码将枚举序列化和反序列化为整数

时间:2018-06-20 14:35:25

标签: java json enums kotlin

我正在研究自定义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吗?

1 个答案:

答案 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)