天天看點

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);}
}
           

總結

我們在使用第三方包的時候遇到類似問題,首先應該可以考慮的是,能不能通過轉換成基礎類型來解決,因為基礎類型是一定支援了(如果不支援,這個第三方包意義不大吧?)。

這樣的話,隻需要在類中更改一下接口實作就可以了。修改成本是極低的。

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