Вот полная реализация, основанная на неполном ответе, предоставленном @ user1556622 и обсуждении в code.google.com / p / google-gson / questions / detail? Id = 43 .
КакВ результате мы можем сериализовать список абстрактных Field
объектов и плавно десериализовать его независимо от конкретной реализации конкретного Field
и глубины его иерархии.
class MyClass { //class which we would like to serialiaze/deserialize
List<Field> fields; //field is an hierarchy of classes
}
/**
* Purpose of this adapter is simple:
* 1) put during serialization in all Field objects additional property describing class
* 2) during deserialization invoke (based on class info) necessary deserializer to create class
*/
public class FieldTypeAdapterFactory implements TypeAdapterFactory {
private static final String CLASS_META_KEY="clz";
Gson gson;
TypeToken<?> type;
TypeAdapter<Field> fieldAdapter;
TypeAdapter<JsonElement> elementAdapter;
TypeAdapterFactory taf;
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!Field.class.isAssignableFrom(type.getRawType()))
return null; // this class only serializes 'Field' and its subtypes
this.type=type;
this.gson=gson;
this.taf=this;
fieldAdapter = gson.getDelegateAdapter(taf, TypeToken.get(Field.class));
elementAdapter = gson.getAdapter(JsonElement.class);
TypeAdapter<T> result = new FieldTypeAdapter<T>();
result.nullSafe();
return result;
}
class FieldTypeAdapter<T> extends TypeAdapter<T> {
public FieldTypeAdapter() {
}
@Override
public void write(JsonWriter out, Object value) throws IOException {
if(value instanceof Field) {
JsonObject object = fieldAdapter.toJsonTree((Field )value).getAsJsonObject();
object.addProperty(CLASS_META_KEY, value.getClass().getCanonicalName());
elementAdapter.write(out, object);
}
else {
elementAdapter.write(out, (JsonElement) value);
}
}
@Override
public T read(JsonReader in) throws IOException {
JsonObject object = elementAdapter.read(in).getAsJsonObject();
if (object.has(CLASS_META_KEY)) {
String className=object.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
TypeAdapter<?> adapter = gson.getDelegateAdapter(taf, TypeToken.get(clz));
return (T) adapter.fromJsonTree(object);
}
catch (Exception e) {
return (T )fieldAdapter.fromJsonTree(object);
}
}
else
return (T )elementAdapter.fromJsonTree(object);
}
}
}
Регистрация фабрики:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new FieldTypeAdapterFactory())
.create();