Es posible crear un TypeAdapter
que delegue uno de sus métodos. Este caso de uso es una parte importante de la API, y existe un método getDelegateAdapter() solo para este propósito. Pase this
como el primer argumento para getDelegateAdapter
que devolverá el adaptador que tiene prioridad después de la fábrica actual.
TypeAdapterFactory immutableListFactory = new TypeAdapterFactory() {
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!(type.getType() instanceof ParameterizedType)
|| !type.getRawType().equals(ImmutableList.class)) {
return null;
}
ParameterizedType parameterizedType = (ParameterizedType) type.getType();
TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
TypeAdapter<?> elementAdapter = gson.getAdapter(
TypeToken.get(parameterizedType.getActualTypeArguments()[0]));
return new ImmutableListAdapter(delegate, elementAdapter);
}
class ImmutableListAdapter<E> extends TypeAdapter<ImmutableList<E>> {
private TypeAdapter<List<E>> delegate;
private TypeAdapter<E> element;
ImmutableListAdapter(TypeAdapter<List<E>> delegate, TypeAdapter<E> element) {
this.delegate = delegate;
this.element = element;
}
@Override public void write(JsonWriter out, ImmutableList<E> value) throws IOException {
delegate.write(out, value);
}
@Override public ImmutableList<E> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
ImmutableList.Builder<E> builder = ImmutableList.builder();
in.beginArray();
while (in.hasNext()) {
builder.add(element.read(in));
}
in.endArray();
return builder.build();
}
}
};
Usted puede mezclar y combinar JsonSerializer
/JsonDeserializer
con TypeAdapterFactory
, pero no directamente. La forma más sencilla es volver a llamar a Gson para serializar valores secundarios en su clase. En este ejemplo se cambiaría el bucle interior a esto:
while (in.hasNext()) {
builder.add(gson.<E>fromJson(in, elementType));
}
La principal diferencia entre JsonSerializer
/JsonDeserializer
y TypeAdapter
es el número de etapas que se necesita para pasar de JSON para su modelo de objetos. Con JsonSerializer
/JsonDeserializer
los objetos se convierten primero al modelo DOM de Gson (JsonElement
etc.) y luego se convierten a su modelo de objetos. Con TypeAdapter
, se omite el paso intermedio.
Esto hace que el código del adaptador de tipo sea un poco más complicado de leer y escribir, por lo que debería preferirlo solo para el código optimizado.
Esta es una gran respuesta. Una de las cien mejores que he leído en este sitio a lo largo de los años. ¡Gracias por tomarse el tiempo de dar un ejemplo realista! Esta respuesta cambió mi punto de vista de Gson por sí solo. – kevinarpe