【发布时间】:2017-04-18 10:17:12
【问题描述】:
假设我们有这个 JSON:
[
{
"__typename": "Car",
"id": "123",
"name": "Toyota Prius",
"numDoors": 4
},
{
"__typename": "Boat",
"id": "4567",
"name": "U.S.S. Constitution",
"propulsion": "SAIL"
}
]
(列表中可能还有更多元素;这里只显示了两个)
我有 Car 和 Boat POJO,它们使用 Vehicle 基类作为公共字段:
public abstract class Vehicle {
public final String id;
public final String name;
}
public class Car extends Vehicle {
public final Integer numDoors;
}
public class Boat extends Vehicle {
public final String propulsion;
}
解析这个 JSON 的结果应该是 List<Vehicle>。问题是没有 JSON 解析器会立即知道 __typename 是如何区分 Boat 和 Car。
使用 Gson,我可以创建一个 JsonDeserializer<Vehicle>,它可以检查 __typename 字段,确定这是 Car 还是 Boat,然后在提供的 JsonDeserializationContext 上使用 deserialize() 来解析特定的JSON 对象转换为适当的类型。这很好用。
但是,我正在构建的特定东西应该支持可插入的 JSON 解析器,我想我会尝试将 Moshi 作为替代解析器。但是,目前 Moshi 文档中没有很好地涵盖这个特殊问题,我很难弄清楚如何最好地解决它。
最接近JsonDeserializer<T> is JsonAdapter<T>。然而,fromJson() 被传递了一个 JsonReader,它有一个破坏性的 API。要找出__typename 是什么,我必须能够从JsonReader 事件中手动解析所有内容。虽然我可以在知道正确的具体类型后调用 adapter() on the Moshi instance 来尝试调用现有的 Moshi 解析逻辑,但我将使用来自 JsonReader 的数据并破坏其提供完整对象描述的能力。
JsonDeserializer<Vehicle> 的另一个类似物是返回 Vehicle 的 @FromJson-annotated method。但是,我无法确定要传递给该方法的简单事物。我唯一能想到的就是创建另一个 POJO 来表示所有可能字段的联合:
public class SemiParsedKindOfVehicle {
public final String id;
public final String name;
public final Integer numDoors;
public final String propulsion;
public final String __typename;
}
然后,理论上,如果我在使用Moshi 注册为类型适配器的类上有@FromJson Vehicle rideLikeTheWind(SemiParsedKindOfVehicle rawVehicle),Moshi 可能能够将我的JSON 对象解析为SemiParsedKindOfVehicle 实例并调用rideLikeTheWind()。在那里,我会查找__typename,识别类型,然后自己完全构建Car 或Boat,返回该对象。
虽然可行,但它比 Gson 方法复杂得多,而且我的 Car/Boat 场景是我需要处理的可能数据结构的简单端。
是否有另一种方法来处理我缺少的 Moshi?
【问题讨论】:
标签: moshi