天天看点

Gson 反序列化注意点

官方github在这里 https://github.com/google/gson

当序列化对象中有uri成员时

public class person {
    private String name;
    private Uri imagePath;
    public setImageUri(Uri path) {imagePath = path;}
    public Uri getImageUri(){return imagePath;}
}
           

这个时候如果反序列化程序会崩溃

原因

查官方文档 https://github.com/google/gson/blob/master/UserGuide.md#TOC-Gson-With-Gradle, 发现:

However, Gson can not automatically deserialize the pure inner classes since their no-args constructor also need a reference to the containing Object which is not available at the time of deserialization.
           

大概就是说,当类中包含有内部类的时候,不能直接deserialize,因为这时指向内部类的无参构造函数还不可用。

可能我们这里并不能算内部类,但原因应该是差不多的。

解决

  • 方法一

    将内部类设为static,即静态的。在这个例子中,就是变成这样,但这显然不符合我们的需求,我们要每一个person对象都有一个头像,而设为static就所有对象共享一个头像了。

public class person {
    private String name;
    // 多了个"static"
    static private Uri imagePath;
    public setImageUri(Uri path) {imagePath = path;}
    public getImageUri(){return imagePath;}
}
           
  • 方法二

    自己实现custom instance creator 接口。

    在StackOverflow找到一个比官方说的更清楚的答案

    https://stackoverflow.com/questions/22533432/create-object-from-gson-string-doesnt-work

    翻译过来大概就是这样:

    首先实现两个类:

// 反序列化器
public class UriSerializer implements JsonSerializer<Uri> {
    public JsonElement serialize(Uri src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(src.toString());
    }
}

// 序列化器
public class UriDeserializer implements JsonDeserializer<Uri> {
    @Override
    public Uri deserialize(final JsonElement src, final Type srcType,
                           final JsonDeserializationContext context) throws JsonParseException {
        return Uri.parse(src.getAsString());
    }
}
           

然后,使用Gson的时候,就要挂在对于Uri的序列化器和反序列化器了,像这样:

// 序列化
Gson gson = new GsonBuilder()
                .registerTypeAdapter(Uri.class, newUriSerializer())
                .create();
String personInString = gson.toJson(myPerson);
// 反序列化
Gson gson = new GsonBuilder()
                    .registerTypeAdapter(Uri.class, new UriDeserializer())
                    .create();
person myPerson = gson.fromJson(personInString, person.class);
           
  • 方法三

    方法三是宿友灵光一闪想出来的。

    既然反序列化失败的原因是,类中存在内部类,那么,如果我们以String方法来保存我们的类呢?String是原生类型,Gson是一定支持的。

    于是有了这个曲线救国的机智方法。

public class person {
    private String name;
    private String imagePath;
    public setImageUri(Uri path) {imagePath = path.toString();}
    public Uri getImageUri(){return Uri.parse(imagePath);}
}
           

总结

我们在使用第三方包的时候遇到类似问题,首先应该可以考虑的是,能不能通过转换成基础类型来解决,因为基础类型是一定支持了(如果不支持,这个第三方包意义不大吧?)。

这样的话,只需要在类中更改一下接口实现就可以了。修改成本是极低的。

如果不能,再考虑其他官方方法。