我想基于type
字段值将json对象反序列化为特定类型的对象(使用Gson库),例如:
[
{
"type": "type1",
"id": "131481204101",
"url": "http://something.com",
"name": "BLAH BLAH",
"icon": "SOME_STRING",
"price": "FREE",
"backgroundUrl": "SOME_STRING"
},
{
....
}
]
因此type
字段将具有不同(但已知)的值。基于该值,我需要将该json对象反序列化为适当的模型对象,例如:Type1Model,Type2Model等。
我知道在反序列化之前我可以轻松地将它转换为JSONArray
,迭代它并解析应该反序列化的类型。但我认为这是一种丑陋的方法,我正在寻找更好的方法。有什么建议吗?
答案 0 :(得分:28)
您可以实现JsonDeserializer
并在将Json值解析为Java实例时使用它。我会尝试用一个能给你这个想法的代码来展示它:
1)定义您的自定义JsonDeserializer
类,它通过传入的json值的id属性创建不同的类实例:
class MyTypeModelDeserializer implements JsonDeserializer<MyBaseTypeModel> {
@Override
public MyBaseTypeModel deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonElement jsonType = jsonObject.get("type");
String type = jsonType.getAsString();
MyBaseTypeModel typeModel = null;
if("type1".equals(type)) {
typeModel = new Type1Model();
} else if("type2".equals(type)) {
typeModel = new Type2Model();
}
// TODO : set properties of type model
return typeModel;
}
}
2)为不同的java对象实例定义基类:
class MyBaseTypeModel {
private String type;
// TODO : add other shared fields here
}
3)定义扩展基类的java对象类的不同实例:
class Type1Model extends MyBaseTypeModel {
// TODO: add specific fields for this class
}
class Type2Model extends MyBaseTypeModel {
// TODO: add specific fields for this class
}
4)在将json值解析为bean时使用这些类:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyBaseTypeModel.class, new MyTypeModelDeserializer());
Gson gson = gsonBuilder.create();
MyBaseTypeModel myTypeModel = gson.fromJson(myJsonString, MyBaseTypeModel.class);
我现在无法测试,但我希望你能得到这个想法。 this link也非常有帮助。
答案 1 :(得分:6)
@ stephane-k的答案有效,但有点令人困惑,可以改进(见他的回答评论)
将https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java复制到您的项目中。 (没关系;这些课程设计为复制/粘贴https://github.com/google/gson/issues/845#issuecomment-217231315)
设置模型继承:
// abstract is optional
abstract class BaseClass {
}
class Type1Model extends BaseClass {
}
class Type2Model extends BaseClass {
}
设置GSON或更新现有的GSON:
RuntimeTypeAdapterFactory<BaseClass> typeAdapterFactory = RuntimeTypeAdapterFactory
.of(BaseClass.class, "type")
.registerSubtype(Type1Model.class, "type1")
.registerSubtype(Type2Model.class, "type2");
Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeAdapterFactory)
.create();
将JSON反序列化为基类:
String jsonString = ...
BaseClass baseInstance = gson.fromJson(jsonString, BaseClass.class);
baseInstance
将是Type1Model
或Type2Model
的实例。
从这里你可以编码到一个界面或检查instanceof和cast。
答案 2 :(得分:2)
然后用
配置它public static final class JsonAdapterFactory extends
RuntimeTypeAdapterFactory<MediumSummaryInfo> {
public JsonAdapterFactory() {
super(MyBaseType.class, "type");
registerSubtype(MySubtype1.class, "type1");
registerSubtype(MySubtype2.class, "type2");
}
}
并添加注释:
@JsonAdapter(MyBaseType.JsonAdapterFactory.class)
到MyBaseType
好多了。
答案 3 :(得分:1)
如果您有很多子类型,并且不想或无法维护它们的列表,则还可以使用基于注释的方法。
这是必需的代码以及一些用法示例: https://gist.github.com/LostMekka/d90ade1fe051732d6b4ac60deea4f9c2 (它是Kotlin,但可以轻松移植到Java)
对我来说,这种方法特别吸引人,因为我编写了一个小型库,该库在编译时并不知道所有可能的子类型。