我认为自定义序列化器/反序列化器是继续进行的唯一方法,我尝试向您建议实现我发现的最紧凑的方法。对于没有使用您的类,我深表歉意,但是想法是一样的(我只想要至少1个基类和2个扩展类)。
baseClass.java
public class baseClass{ @Override public String toString() { return "baseClass [list=" + list + ", isA=" + isA + ", x=" + x + "]"; } public ArrayList<baseClass> list = new ArrayList<baseClass>(); protected String isA="baseClass"; public int x; }ExtendedClass1.java
public class ExtendedClass1 extends baseClass{ @Override public String toString() { return "ExtendedClass1 [total=" + total + ", number=" + number + ", list=" + list + ", isA=" + isA + ", x=" + x + "]"; } public ExtendedClass1(){ isA = "ExtendedClass1"; } public Long total; public Long number;}ExtendedClass2.java
public class ExtendedClass2 extends baseClass{ @Override public String toString() { return "ExtendedClass2 [total=" + total + ", list=" + list + ", isA=" + isA + ", x=" + x + "]"; } public ExtendedClass2(){ isA = "ExtendedClass2"; } public Long total;}CustomDeserializer.java
public class CustomDeserializer implements JsonDeserializer<List<baseClass>> { private static Map<String, Class> map = new TreeMap<String, Class>(); static { map.put("baseClass", baseClass.class); map.put("ExtendedClass1", ExtendedClass1.class); map.put("ExtendedClass2", ExtendedClass2.class); } public List<baseClass> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { List list = new ArrayList<baseClass>(); JsonArray ja = json.getAsJsonArray(); for (JsonElement je : ja) { String type = je.getAsJsonObject().get("isA").getAsString(); Class c = map.get(type); if (c == null) throw new RuntimeException("Unknow class: " + type); list.add(context.deserialize(je, c)); } return list; }}CustomSerializer.java
public class CustomSerializer implements JsonSerializer<ArrayList<baseClass>> { private static Map<String, Class> map = new TreeMap<String, Class>(); static { map.put("baseClass", baseClass.class); map.put("ExtendedClass1", ExtendedClass1.class); map.put("ExtendedClass2", ExtendedClass2.class); } @Override public JsonElement serialize(ArrayList<baseClass> src, Type typeOfSrc, JsonSerializationContext context) { if (src == null) return null; else { JsonArray ja = new JsonArray(); for (baseClass bc : src) { Class c = map.get(bc.isA); if (c == null) throw new RuntimeException("Unknow class: " + bc.isA); ja.add(context.serialize(bc, c)); } return ja; } }}现在,这是我用来测试整个程序的代码:
public static void main(String[] args) { baseClass c1 = new baseClass(); ExtendedClass1 e1 = new ExtendedClass1(); e1.total = 100L; e1.number = 5L; ExtendedClass2 e2 = new ExtendedClass2(); e2.total = 200L; e2.x = 5; baseClass c2 = new baseClass(); c1.list.add(e1); c1.list.add(e2); c1.list.add(c2); List<baseClass> al = new ArrayList<baseClass>(); // this is the instance of baseClass before serialization System.out.println(c1); GsonBuilder gb = new GsonBuilder(); gb.registerTypeAdapter(al.getClass(), new CustomDeserializer()); gb.registerTypeAdapter(al.getClass(), new CustomSerializer()); Gson gson = gb.create(); String json = gson.toJson(c1); // this is the corresponding json System.out.println(json); baseClass newC1 = gson.fromJson(json, baseClass.class); System.out.println(newC1);}这是我的处决:
baseClass [list=[ExtendedClass1 [total=100, number=5, list=[], isA=ExtendedClass1, x=0], ExtendedClass2 [total=200, list=[], isA=ExtendedClass2, x=5], baseClass [list=[], isA=baseClass, x=0]], isA=baseClass, x=0]{"list":[{"total":100,"number":5,"list":[],"isA":"ExtendedClass1","x":0},{"total":200,"list":[],"isA":"ExtendedClass2","x":5},{"list":[],"isA":"baseClass","x":0}],"isA":"baseClass","x":0}baseClass [list=[ExtendedClass1 [total=100, number=5, list=[], isA=ExtendedClass1, x=0], ExtendedClass2 [total=200, list=[], isA=ExtendedClass2, x=5], baseClass [list=[], isA=baseClass, x=0]], isA=baseClass, x=0]一些解释:该技巧由串行器/解串器中的另一个Gson完成。我只使用
isA字段来发现合适的班级。为了更快,我使用地图将
isA字符串关联到相应的类。然后,我使用第二个Gson对象进行适当的序列化/反序列化。我将其声明为静态,因此您不会因多次分配Gson而减慢序列化/反序列化。
Pro 实际上,您编写的代码并不比这更多,而是让Gson完成所有工作。您只需要记住在地图中放置一个新的子类(例外使您想起了这一点)。
缺点 您有两张地图。我认为我的实现可以做些改进以避免映射重复,但是我将它们留给您(或将来的编辑器,如果有的话)。
也许您想将序列化和反序列化统一为一个唯一的对象,应该检查
TypeAdapter类或尝试使用同时实现两个接口的对象。



