我正在使用Moshi从我们的服务器反序列化json,但我遇到了一个问题,我确信有一个解决方案,我只是看不到它。在套接字上,我们发送json,在顶层有三个字段:
{
"data_type": "<actual_data_type>",
"data_id": "<actual_data_id>",
"data": <data_object>
}
问题是data
实际上可能是几个不同的对象,基于data_type
是什么我不能确定如何将该信息传递到适配器Data
。我尝试了几个不同的东西,但它越来越接近我自己解析整个事情,这似乎打败了这一点。有没有办法将信息从一个适配器传递到另一个适配器?
答案 0 :(得分: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适配器能够启动并为我们进行正确的解析。