今天遇到一个Json反序列化的问题,反序列化的对象都是别人封装好的,类似下面的例子:
有一个待序列化的Company类,它持有一个People列表。
class Company {
List<People> peoples;
/**
* 构造函数.
*
* @param peoples
*/
public Company(List<People> peoples) {
this.peoples = peoples;
}
。。。若干getter/setter方法
@Override
public String toString() {
// TODO Auto-generated method stub
if (peoples != null && peoples.size() > 0) {
String str = "";
for (People people : peoples) {
str += people.toString();
}
return str;
}
return super.toString();
}
}
interface People {
}
class Man implements People {
private String name;
private int age;
/**
* 构造函数.
*
* @param name
* @param age
*/
public Man(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name : " + name + " age : " + age;
}
。。。若干getter/setter方法
}
测试用例:
Company company = new Company(new ArrayList<People>());
company.getPeoples().add(new Man("better future", 20));
Gson gson = new Gson();
String jsonString = gson.toJson(company);
System.out.println(jsonString);
Company company1 = gson.fromJson(jsonString, Company.class);
System.out.println(company1);
看着没有问题,但是
Exception in thread “main” java.lang.RuntimeException: Unable to invoke no-args constructor for interface better517na.People. Register an InstanceCreator with Gson for this type may fix this problem.
Why?不能执行People的无参构造函数?People是接口呀,哪来的构造函数?这就是问题的所在了,幸好Gson提供了一种解决办法,实现一个People类的TypeAdapter来完成了People的序列化。
如下:
class PeopleTypeAdapter implements JsonSerializer<People>, JsonDeserializer<People> {
@Override
public People deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
Gson gson = new Gson();
return gson.fromJson(arg0, Man.class);
}
@Override
public JsonElement serialize(People arg0, Type arg1, JsonSerializationContext arg2) {
Gson gson = new Gson();
return gson.toJsonTree(arg0);
}
}
测试代码:
Company company = new Company(new ArrayList<People>());
company.getPeoples().add(new Man("better future", 20));
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(People.class, new PeopleTypeAdapter());
Gson gson = builder.create();
// Gson gson = new Gson();
String jsonString = gson.toJson(company);
System.out.println(jsonString);
Company company1 = gson.fromJson(jsonString, Company.class);
System.out.println(company1);
运行结果:
{“peoples”:[{“name”:”better future”,”age”:20}]}
name : better future age : 20
这里在Company反序列化时,我指定了People的实现类Man。那么问题来了,这样真的好吗?易于扩展吗?我们在Company中使用People接口,而不指定具体的实现类不就是为了扩展性吗?现在好了,管他序列化之前使用的是哪个People,一股脑全使用Man。怎么办呢?我们可以为People的每个实现类实现一个TypeAdapter呀!!这样真的好吗?说好的可扩展呢?
对此,我找了很多其他的Json序列化工具,对于这个问题,解决的办法大同小异。比较方便的是在反序列化时,指定需要特别注意的字段的Class类型,当然也有人说,我们不用接口呀!但你使用的第三方库呢?你能保证吗?
这个导致了我想到一个更近一步的解决方案,由我们先构造出反序列化的对象,然后将它传给Json工具,由Json工具将JsonString中的信息保存到我们构造的对象中,这样Json工具的职责就更明确了,负责json的序列化或反序列化,而不是构造对象。