1

我正在使用 Moshi 从我们的服务器反序列化 json,但我遇到了一个问题,我确定有解决方案,但我看不到它。通过套接字,我们发送 json,它在顶层具有三个字段:

{
    "data_type": "<actual_data_type>",
    "data_id": "<actual_data_id>",
    "data": <data_object>
}

问题是data实际上可以是几个不同的对象,具体取决于什么data_type我不确定如何将该信息传递到Data. 我尝试了一些不同的事情,但它越来越接近我自己解析整个事情,这似乎打破了这一点。有没有办法将信息从一个适配器传递到另一个适配器?

4

1 回答 1

0

对于任何想做类似事情的人,我从这里采用了通用工厂的基本形状:https ://github.com/square/moshi/pull/264/files (这也是@eric cochran在他的评论中推荐的) 并使其更具体以适合我的确切情况。

class EventResponseAdapterFactory : JsonAdapter.Factory {
    private val labelKey = "data_type"
    private val subtypeToLabel = hashMapOf<String, Class<out BaseData>>(
        DataType.CURRENT_POWER.toString() to CurrentPower::class.java,
        DataType.DEVICE_STATUS_CHANGED.toString() to DeviceStatus::class.java,
        DataType.EPISODE_EVENT.toString() to EpisodeEvent::class.java,
        DataType.APPLIANCE_INSTANCE_UPDATED.toString() to ApplianceInstanceUpdated::class.java,
        DataType.RECURRING_PATTERNS.toString() to RecurringPatternOccurrence::class.java,
        DataType.RECURRING_PATTERN_UPDATED.toString() to RecurringPatternUpdated::class.java
    )

    override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
        if (!annotations.isEmpty() || type != EventResponse::class.java) {
            return null
        }

        val size = subtypeToLabel.size
        val labelToDelegate = LinkedHashMap<String, JsonAdapter<EventResponse<BaseData>>>(size)
        for (entry in subtypeToLabel.entries) {
            val key = entry.key
            val value = entry.value
            val parameterizedType = Types.newParameterizedType(EventResponse::class.java, value)
            val delegate = moshi.adapter<EventResponse<BaseData>>(parameterizedType, annotations)
            labelToDelegate.put(key, delegate)
        }

        return EventResponseAdapter(
            labelKey,
            labelToDelegate
        )
    }

    private class EventResponseAdapter internal constructor(
        private val labelKey: String,
        private val labelToDelegate: LinkedHashMap<String, JsonAdapter<EventResponse<BaseData>>>
    ) : JsonAdapter<EventResponse<BaseData>>() {

        override fun fromJson(reader: JsonReader): EventResponse<BaseData>? {
            val raw = reader.readJsonValue()
            if (raw !is Map<*, *>) {
                throw JsonDataException("Value must be a JSON object but had a value of $raw of type ${raw?.javaClass}")
            }

            val label = raw.get(labelKey) ?: throw JsonDataException("Missing label for $labelKey")
            if (label !is String) {
                throw JsonDataException("Label for $labelKey must be a string but had a value of $label of type ${label.javaClass}")
            }
            val delegate = labelToDelegate[label] ?: return null
            return delegate.fromJsonValue(raw)
        }

        // Not used
        override fun toJson(writer: JsonWriter, value: EventResponse<BaseData>?) {}
    }
}

唯一需要注意的是RuntimeJsonAdapterFactory链接中的 用于Types.getRawType(type)获取剥离了泛型的类型。当然,我们不希望这样,因为一旦找到特定的泛型类型,我们希望正常的 Moshi 适配器启动并为我们进行正确的解析。

于 2018-03-28T08:13:02.730 回答