java 如何使用多态处理反序列化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15736654/
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
How to handle deserializing with polymorphism?
提问by user1219278
I have a class like:
我有一个类:
public class Barn {
String type;
Animal animal;
}
public class Horse extends Animal {
}
public class Cow extends Animal {
}
and I want to serialize a list of them:
我想序列化它们的列表:
List<Barn> barns = new ArrayList<Barn>();
Barn barn1 = new Barn();
barn1.setType("horse");
barn1.setAnimal(new Horse());
barns.add(barn1);
Barn barn2 = new Barn();
barn2.setType("cow");
barn2.setAnimal(new Cow());
barns.add(barn2);
...
Group<Barn> barns = gson.fromJson(serialized);
When I serialize, type information will be lost for the Animal attribute. Is there a way I could install a parser listener somehow so that I could provide the right class to deserialize as when each element in the list is encountered? That was the idea behind manually supplying a string describing the class type.
当我序列化时,Animal 属性的类型信息将丢失。有没有办法以某种方式安装解析器侦听器,以便在遇到列表中的每个元素时提供正确的类进行反序列化?这就是手动提供描述类类型的字符串背后的想法。
Thanks
谢谢
采纳答案by Programmer Bruce
In the Gson project code base is the RuntimeTypeAdapter, which reportedly works well for polymorphic serialization and deserialization. I don't think I've yet tried to use it. See http://code.google.com/p/google-gson/issues/detail?id=231for more info. Note, it hasn't yet been included in any Gson releases.
Gson 项目的代码库是RuntimeTypeAdapter,据报道它适用于多态序列化和反序列化。我想我还没有尝试使用它。有关详细信息,请参阅http://code.google.com/p/google-gson/issues/detail?id=231。请注意,它尚未包含在任何 Gson 版本中。
If use of it doesn't fit your needs, then custom deserialization processing is necessary. Following is one such approach, assuming you want to use the JSON structure demonstrated. (I'd take a somewhat different approach, if the JSON structure could be different.)
如果使用它不符合您的需求,则需要自定义反序列化处理。下面是一种这样的方法,假设您要使用演示的 JSON 结构。(如果 JSON 结构可能不同,我会采取一些不同的方法。)
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
public class App
{
public static void main(String[] args)
{
Barn[] barns = {new Barn(), new Barn()};
barns[0].type = "horse";
barns[0].animal = new Horse();
barns[1].type = "cow";
barns[1].animal = new Cow();
String json = new Gson().toJson(barns);
// [{"type":"horse","animal":{}},{"type":"cow","animal":{}}]
BarnDeserializer deserializer = new BarnDeserializer("type");
deserializer.registerBarnType("horse", Horse.class);
deserializer.registerBarnType("cow", Cow.class);
Gson gson = new GsonBuilder().registerTypeAdapter(Barn.class, deserializer).create();
List<Barn> barns2= gson.fromJson(json, new TypeToken<List<Barn>>(){}.getType());
for (Barn barn : barns2)
{
System.out.println(barn.animal.getClass());
}
}
}
class BarnDeserializer implements JsonDeserializer<Barn>
{
String barnTypeElementName;
Gson gson;
Map<String, Class<? extends Animal>> barnTypeRegistry;
BarnDeserializer(String barnTypeElementName)
{
this.barnTypeElementName = barnTypeElementName;
gson = new Gson();
barnTypeRegistry = new HashMap<>(); // Java 7 required for this syntax.
}
void registerBarnType(String barnTypeName, Class<? extends Animal> animalType)
{
barnTypeRegistry.put(barnTypeName, animalType);
}
@Override
public Barn deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
JsonObject barnObject = json.getAsJsonObject();
JsonElement animalTypeElement = barnObject.get(barnTypeElementName);
Barn barn = new Barn();
barn.type = animalTypeElement.getAsString();
Class<? extends Animal> animalType = barnTypeRegistry.get(barn.type);
barn.animal = gson.fromJson(barnObject.get("animal"), animalType);
return barn;
}
}
class Barn {String type; Animal animal;}
class Animal {}
class Horse extends Animal {}
class Cow extends Animal {}
回答by julman99
You could use Gson Firefor this. The code would look something like this:
您可以为此使用Gson Fire。代码看起来像这样:
GsonFireBuilder builder = new GsonFireBuilder()
.registerTypeSelector(Barn.class, new TypeSelector<Barn>() {
@Override
public Class<? extends Barn> getClassForElement(JsonElement readElement) {
String type = readElement.getAsJsonObject().get("type").getAsString();
if(type.equals("horse")){
return Horse.class;
} else if(type.equals("cow")) {
return Cow.class;
} else {
return null; //returning null will trigger Gson's default behavior
}
}
});
Gson gson = builder.createGson();
回答by db80
You don't need to write your own Adapter.
您不需要编写自己的适配器。
Finally gson has its own RuntimeTypeAdapterFactoryto handle java polymorphism but unfortunately it's not part of the gson core library (in order to use it you must copy and paste the class into your project).
最后,gson 有自己的RuntimeTypeAdapterFactory来处理 java 多态性,但不幸的是它不是 gson 核心库的一部分(为了使用它,您必须将该类复制并粘贴到您的项目中)。
Suppose that you have this Animal.class
:
假设你有这个Animal.class
:
public class Animal {
protected String name;
protected String type;
public Animal(String name, String type) {
this.name = name;
this.type = type;
}
}
And Horse.class
:
并且Horse.class
:
public class Horse extends Animal {
public Horse(String name) {
super(name, "horse");
}
}
You can initialize the RuntimeTypeAdapterFactory
using the code below:
您可以RuntimeTypeAdapterFactory
使用以下代码初始化:
RuntimeTypeAdapterFactory<Animal> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
.of(Animal.class, "type")
.registerSubtype(Horse.class, "horse")
.registerSubtype(Cow.class, "cow");
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(runtimeTypeAdapterFactory)
.create();
Hereyou can find a full working example.
在这里你可以找到一个完整的工作示例。
回答by Daniele Segato
I'm also interested in the feature and I've added a feature request to GSon
我也对这个功能感兴趣,我已经向 GSon 添加了一个功能请求