Tyl*_*itt 15 java serialization interface list gson
我在GSON中遇到了一些奇怪的行为.
如果我有以下类结构:
public interface Animal {
public void nothing();
}
public class Cat implements Animal {
private String name;
public Cat(String name) {
super();
this.name = name;
}
public Cat(){}
@Override
public void nothing() {
// TODO Auto-generated method stub
};
}
public class Dog implements Animal {
private String name;
public Dog(String name) {
super();
this.name = name;
}
public Dog(){}
@Override
public void nothing() {
// TODO Auto-generated method stub
};
}
Run Code Online (Sandbox Code Playgroud)
我可以做这个:
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Cat("Betty"));
animals.add(new Dog("Fred"));
System.out.println(gson.toJson(animals));
Run Code Online (Sandbox Code Playgroud)
得到这个输出:
[{"name":"Betty"},{"name":"Fred"}]
Run Code Online (Sandbox Code Playgroud)
但是,如果我放入animals一个包含类:
public class Container {
List<Animal> animals = new ArrayList<Animal>();
public void addAnimal(Animal a){
animals.add(a);
}
}
Run Code Online (Sandbox Code Playgroud)
并致电:
Container container = new Container();
container.addAnimal(new Cat("betty"));
System.out.println(gson.toJson(container));
Run Code Online (Sandbox Code Playgroud)
我明白了:
{"animals":[{}]}
Run Code Online (Sandbox Code Playgroud)
看起来GSON可以List<Interface>在该列表本身时序列化接口列表,但是当列表包含在另一个类中时,GSON会出现问题.
知道我做错了什么吗?
作为旁注,我可以使用自定义反序列化器正确地将json字符串反序列化为正确的类型.这是给我提出问题的序列化.
谢谢
简单地使用显式获取对象类的自定义 JsonSerializer 就足够了(由于某种原因,大概 Gson 获取了声明的类型)。这是序列化接口的通用解决方案:
public static class InterfaceSerializer<T> implements JsonSerializer<T> {
public JsonElement serialize(T link, Type type,
JsonSerializationContext context) {
// Odd Gson quirk
// not smart enough to use the actual type rather than the interface
return context.serialize(link, link.getClass());
}
}
Run Code Online (Sandbox Code Playgroud)
对于您的示例,我可以执行以下操作:
GsonBuilder gbuild = new GsonBuilder();
Gson standard = gbuild.create();
ArrayList<Animal> animals = Lists.newArrayList(new Cat("Betty"),new Dog("Fred"));
System.out.println(standard.toJson(animals));
Container c = new Container();
c.animals.addAll(animals);
System.out.println(standard.toJson(c));
Gson interfaceAware = gbuild
.registerTypeAdapter(Animal.class, new InterfaceSerializer<>()).create();
System.out.println(interfaceAware.toJson(c));
Run Code Online (Sandbox Code Playgroud)
这输出:
[{"name":"Betty","hates":"Everything"},{"name":"Fred","loves":"Everything"}]
{"animals":[{},{}]}
{"animals":[{"name":"Betty","hates":"Everything"}, "name":"Fred","loves":"Everything"}]}
Run Code Online (Sandbox Code Playgroud)
最后一项是正确序列化的字符串。
不幸的是,这不足以反序列化 JSON,因为生成的 JSON 不包含任何类型信息。查看如何使用接口序列化类的答案?一种跟踪对象类型的方法,从而序列化/反序列化对象。
它远非漂亮,但我现在使用的解决方案是使用
JsonObject jsonObject = gson.toJsonTree(container).getAsJsonObject();
Run Code Online (Sandbox Code Playgroud)
构建一个JsonObject.然后我打电话给:
jsonObject.remove("animals");
jsonObject.add("animals",gson.toJsonTree(container.getAnimals()));
Run Code Online (Sandbox Code Playgroud)
和waa laa,正确的json形式的对象.
加分点:我有一个嵌套容器列表,所以我必须构造一个JsonArray,以便我可以迭代我的容器并在每个容器上调用我的自定义toJson().
故事的道德:使用.添加界面列表
jsonObject.remove();
jsonObject.add(propertyName, property);
Run Code Online (Sandbox Code Playgroud)
使用JsonArray处理容器和遍历容器列表(在列表上只使用toJson()不会在子容器上调用您的特殊方法).
绝对还在寻找更自然的解决方案.
快乐的编码
| 归档时间: |
|
| 查看次数: |
6229 次 |
| 最近记录: |