ActiveAndroid是安卓開發常用的ORM框架。
Gson則是Google提供的輕量級序列化框架,非常適合Android開發使用。
但這兩者同時使用,會產生序列化失敗的問題。你通常會收到如下信息:
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: [your model]. Forgot to register a type adapter?
這是由於ActiveAndroid框架需要模型繼承com.activeandroid.Model類,而這個類貌似不能序列化,具體原因未深究,有興趣的同學可以看看ActiveAndroid的源碼。
在ActiveAndroid的Git上查閱了Issue后,發現有開發者遇到類似問題,但沒有有效解決辦法。
翻閱了Gson API之后,發現Google已經提供了解決途徑。
假設我們有一個基礎類ClassBase:
import java.io.Serializable; public class ClassBase implements Serializable { /** * -6454847757470885679L */ private static final long serialVersionUID = -6454847757470885679L; private String name; private int count; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }
另有一個擴展類Cnblogs:
import java.io.Serializable; public class Cnblogs extends ClassBase implements Serializable { /** * 8568957562120574502L */ private static final long serialVersionUID = 8568957562120574502L; private String welcome; private int members; private String url; public String getGuid() { return welcome; } public void setGuid(String welcome) { this.welcome = welcome; } public int getMembers() { return members; } public void setMembers(int members) { this.members = members; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
如果我們在序列化時想要忽略父類的屬性,怎么辦呢?
這時候,你需要com.google.gson.ExclusionStrategy接口來處理這個問題。
import com.google.gson.ExclusionStrategy; import com.google.gson.FieldAttributes; public class SpecificClassExclusionStrategy implements ExclusionStrategy { private final Class<?> excludedThisClass; private final Class<?> excludedThisClassFields; /*** * 過濾器初始化 * * @param excludedThisClass * 該類和繼承自該類的對象實例將被忽略 * @param excluedThisClassFields * 該類的屬性將不被序列化 */ public SpecificClassExclusionStrategy(Class<?> excludedThisClass, Class<?> excluedThisClassFields) { this.excludedThisClass = excludedThisClass; this.excludedThisClassFields = excluedThisClassFields; } @Override public boolean shouldSkipClass(Class<?> clazz) { if (clazz == null) return false; if (clazz.equals(excludedThisClass)) return true; return shouldSkipClass(clazz.getSuperclass()); } @Override public boolean shouldSkipField(FieldAttributes f) { return f.getDeclaringClass().equals(excludedThisClassFields); } }
再看看這個如何使用,
import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(String[] args) { Cnblogs bl = new Cnblogs(); bl.setName("Cnblogs"); // 設置父類屬性 bl.setCount(1); bl.setWelcome("代碼改變世界"); // 設置當前類屬性 bl.setMembers(176473); bl.setUrl("http://www.cnblogs.com");
Gson gson = new Gson(); // 通常我們使用的初始化方法 System.out.println(gson.toJson(bl));
// 使用了過濾器的初始化方法 Gson gson2 = new GsonBuilder().setExclusionStrategies(new SpecificClassExclusionStrategy(null, ClassBase.class)).create(); System.out.println(gson2.toJson(bl)); } }
兩條打印語句結果如下:
{"welcome":"代碼改變世界","members":2030103,"url":"http://www.cnblogs.com","name":"Cnblogs","count":1} {"welcome":"代碼改變世界","members":2030103,"url":"http://www.cnblogs.com"}
因此,我們只需要在項目中,將gson實例的創建方式改為gson2,並將過濾類的構造函數第二個參數設為com.activeandroid.Model.class,序列化就成功了!
至於第一個參數,比如類A,則任何類A的實例或者繼承自類A的類的實例,在序列化時都會返回null值,即不被序列化。
更復雜的序列化過濾規則,可以通過調整SpecificClassExclusionStrategy類中,兩個重寫方法來實現。