Java Gson - 基于字段值反序列化为特定对象类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21767485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Gson - deserialization to specific object type based on field value
提问by lukaleli
I want to deserialize json objects to specific types of objects (using Gson library) based on type
field value, eg.:
我想根据type
字段值将 json 对象反序列化为特定类型的对象(使用 Gson 库),例如:
[
{
"type": "type1",
"id": "131481204101",
"url": "http://something.com",
"name": "BLAH BLAH",
"icon": "SOME_STRING",
"price": "FREE",
"backgroundUrl": "SOME_STRING"
},
{
....
}
]
So type
field will have different (but known) values. Based on that value I need to deserialize that json object to appropriate model object, eg.: Type1Model, Type2Model etc.
I know I can easily do that before deserialization by converting it to JSONArray
, iterate through it and resolve which type it should be deserialized to. But I think it's ugly approach and I'm looking for better way. Any suggestions?
因此type
字段将具有不同(但已知)的值。基于该值,我需要将该 json 对象反序列化为适当的模型对象,例如:Type1Model、Type2Model 等。我知道我可以在反序列化之前轻松地将其转换为JSONArray
、遍历它并解析它应该反序列化为哪种类型. 但我认为这是丑陋的方法,我正在寻找更好的方法。有什么建议?
采纳答案by Devrim
You may implement a JsonDeserializer
and use it while parsing your Json value to a Java instance. I'll try to show it with a code which is going to give you the idea:
您可以JsonDeserializer
在将 Json 值解析为 Java 实例时实现并使用它。我将尝试用一个代码来展示它,它会给你这个想法:
1) Define your custom JsonDeserializer
class which creates different instance of classes by incoming json value's id property:
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) Define a base class for your different instance of java objects:
2)为不同的java对象实例定义一个基类:
class MyBaseTypeModel {
private String type;
// TODO : add other shared fields here
}
3) Define your different instance of java objects' classes which extend your base class:
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) Use these classes while parsing your json value to a bean:
4) 在将 json 值解析为 bean 时使用这些类:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyBaseTypeModel.class, new MyTypeModelDeserializer());
Gson gson = gsonBuilder.create();
MyBaseTypeModel myTypeModel = gson.fromJson(myJsonString, MyBaseTypeModel.class);
I can not test it right now but I hope you get the idea. Also this linkwould be very helpful.
我现在无法测试它,但我希望你能明白。此外,此链接将非常有帮助。
回答by stephane k.
then configure it with
然后配置它
public static final class JsonAdapterFactory extends
RuntimeTypeAdapterFactory<MediumSummaryInfo> {
public JsonAdapterFactory() {
super(MyBaseType.class, "type");
registerSubtype(MySubtype1.class, "type1");
registerSubtype(MySubtype2.class, "type2");
}
}
and add the annotation:
并添加注释:
@JsonAdapter(MyBaseType.JsonAdapterFactory.class)
@JsonAdapter(MyBaseType.JsonAdapterFactory.class)
to MyBaseType
到 MyBaseType
Much better.
好多了。
回答by tir38
@stephane-k 's answer works, but it is a bit confusing and could be improved upon (see comments to his answer)
@stephane-k 的回答有效,但有点令人困惑,可以改进(请参阅对他的回答的评论)
Copy https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.javainto your project. (It's ok; these classes are designed to be copy/pasted https://github.com/google/gson/issues/845#issuecomment-217231315)
将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)
Setup model inheritance:
设置模型继承:
// abstract is optional
abstract class BaseClass {
}
class Type1Model extends BaseClass {
}
class Type2Model extends BaseClass {
}
Setup GSON or update existing GSON:
设置 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();
Deserialize your JSON into base class:
将您的 JSON 反序列化为基类:
String jsonString = ...
BaseClass baseInstance = gson.fromJson(jsonString, BaseClass.class);
baseInstance
will be instanceof either Type1Model
or Type2Model
.
baseInstance
将是 instanceofType1Model
或Type2Model
。
From here you can either code to an interface or check instanceof and cast.
从这里您可以编码到接口或检查 instanceof 和强制转换。
回答by LostMekkaSoft
If you have a lot of sub types and you do not want to or cannot maintain a list of them, you can also use an annotation based approach.
如果您有很多子类型并且您不想或无法维护它们的列表,您也可以使用基于注释的方法。
Here is the required code and also some usage examples: https://gist.github.com/LostMekka/d90ade1fe051732d6b4ac60deea4f9c2(it is Kotlin, but can easily be ported to Java)
这是所需的代码和一些使用示例:https: //gist.github.com/LostMekka/d90ade1fe051732d6b4ac60deea4f9c2(它是 Kotlin,但可以轻松移植到 Java)
For me, this approach is especially appealing, since I write a small library that does not know all possible sub types at compile time.
对我来说,这种方法特别有吸引力,因为我编写了一个在编译时不知道所有可能子类型的小型库。