gson is a great library - it works well. Sometimes I have custom requirements, and can make and register TypeAdapters and TypeAdaptorFactories - and that works well too. <
actually that seemed to work - getting the adapter for object - using the typeadaptorfactory to discover a "json" method on an object, and having that store away the adaptor object. Seems astonishingly complex for what is such an obvious use case?
eg:
public static @Nullable
TypeAdapter<ImmutableStack<?>> json(final Gson gson)
{
final TypeAdapter<Object> adaptor = gson.getAdapter(Object.class);
return new TypeAdapter<ImmutableStack<?>>()
{
@Override
public ImmutableStack<?> read(@Nullable final JsonReader in) throws IOException
{
throw ProgramError.notImplementedYet();
}
@Override
public void write(final JsonWriter out, final ImmutableStack<?> value) throws IOException
{
out.beginArray();
for (final Object inner : value)
adaptor.write(out, inner);
out.endArray();
}
};
}
does anyone know a better way to do it?
In this case its better to use a JsonSerializer as opposed to a TypeAdapter, for the simple reason that serializers have access to their serialization context:
public class PairSerializer implements JsonSerializer<Pair> {
public PairSerializer() {
super();
}
@Override
public JsonElement serialize(final Pair value, final Type type,
final JsonSerializationContext context) {
final JsonObject jsonObj = new JsonObject();
jsonObj.add("first", context.serialize(value.getFirst()));
jsonObj.add("second", context.serialize(value.getSecond()));
return jsonObj;
}
}
The above sample code illustrates how to delegate serialization of target objects back to the main marshaller. The main advantage of this (apart from avoiding complicated workarounds) is that you can still take advantage of other type adaptors and custom serializers that might have been registered in the main context. Note that registration of serializers and adapters use the exact same code:
// With adapter
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
new PairAdapter()).create();
// With serializer
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
new PairSerializer()).create();
If you find that you need to stick with an adapter, then you can use an embedded Gson proxy to serialize the Pair properties for you, with the disadvantage that you lose access to custom registrations that you made on the parent Gson proxy:
public class PairAdapter extends TypeAdapter<Pair> {
final Gson embedded = new Gson();
public PairAdapter() {
super();
}
@Override
public void write(final JsonWriter out, final Pair value)
throws IOException {
out.beginObject();
out.name("first");
embedded.toJson(embedded.toJsonTree(value.getFirst()), out);
out.name("second");
embedded.toJson(embedded.toJsonTree(value.getSecond()), out);
out.endObject();
}
@Override
public Pair read(JsonReader in) throws IOException {
throw new UnsupportedOperationException();
}
}