【问题标题】:Serialize Generics via enum using moshi使用 moshi 通过枚举序列化泛型
【发布时间】:2021-04-09 07:40:21
【问题描述】:

背景

使用 Moshi,我想为指向一个类的枚举创建通用适配器 我想使用枚举类型,因为在元素的更下方,我有复杂的结构,可以进一步归结为不同的类型。

是否可以通过 via Moshi 以这种方式进行序列化?

我尝试制作一个可以处理 Attempt 中任何类型的通用适配器,但到目前为止我只有 clazz 对象,而不是实际的 T。

Json 示例

{
  "items": [
    {
      "type": "A",
      "apple": "123 Apples"
    },
    {
      "type": "B",
      "organge": "Banana 12",
      "info": {}
    },
    {
      "type": "C",
      "grapes": "Green",
      "quantity": {
        "inStock": "12",
        "offShelf": "12"
      }
    }
  ]
}

类结构

classs FruitResponse(val items: List<FruitTypes>)


@JsonClass(generateAdapter = false)
enum class FruitType(val clazz: Class<*>) {

    A(Apple::class.java),

    B(Banana::class.java),

    C(Grapes::class.java)
}

尝试

class FruitsAdapter<T : Enum<*>>(enumType: Class<T>) : JsonAdapter<T>() {

    private val nameStrings: Array<String?>
    private val nameConstantMap: MutableMap<String, T>

    init {
        try {
            val constants = enumType.enumConstants
            nameStrings = arrayOfNulls<String>(constants?.size ?: 0)
            nameConstantMap = LinkedHashMap()
            constants?.forEachIndexed { index, constant ->
                val annotation = enumType.getField(constant.name).getAnnotation(Json::class.java)
                val name = annotation?.name ?: constant.name
                nameConstantMap[name] = constant
                nameStrings[index] = name
            }
        } catch (e: NoSuchFieldException) {
            throw AssertionError("Missing field in ${enumType.name}")
        }
    }

    @Throws(IOException::class)
    override fun fromJson(reader: JsonReader): T {
        val name = reader.nextString()
        val constant = nameConstantMap[name]
        if (constant != null) return constant
        throw JsonDataException(
            "Expected one of ${Arrays.asList(*nameStrings)} " +
                "but was $name at path ${reader.path}"
        )
    }

    @Throws(IOException::class)
    override fun toJson(writer: JsonWriter, value: T?) {
        val newValue = nameConstantMap.filter { value == it.value }.map { it.key }.firstOrNull()
        if (newValue != null) writer.value(newValue) else writer.nullValue()
    }
}


// Usage
  val moshiAdapter = Moshi.Builder()
        .add(
            FruitType::class.java,
            FruitsAdapter(FruitType::class.java)
        ).build()

【问题讨论】:

    标签: android kotlin generics moshi


    【解决方案1】:

    看看PolymorphicJsonAdapterFactory 可以在moshi-adapters 工件中找到。

    如果您想避免手动编写多态适配器的样板,还有moshi-sealed

    【讨论】:

      猜你喜欢
      • 2017-04-18
      • 1970-01-01
      • 2017-02-03
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多