leech leech - 3 months ago 77
Java Question

Gson Polymorphic Serialization

using Gson 2.2.2 I'm trying to serialize an array list of POJOs (Behaviors).

i have an adapter that's pretty much a copy of what i've seen online:

public class BehaviorAdapter implements JsonSerializer<Behavior> {

private static final String CLASSNAME = "CLASSNAME";
private static final String INSTANCE = "INSTANCE";

@Override
public JsonElement serialize(Behavior src, Type typeOfSrc,
JsonSerializationContext context) {

JsonObject retValue = new JsonObject();
String className = src.getClass().getCanonicalName();
retValue.addProperty(CLASSNAME, className);
JsonElement elem = context.serialize(src);
retValue.add(INSTANCE, elem);
return retValue;
}
}


The i register it like this:

GsonBuilder builder = new GsonBuilder();
builder.registerTypeHierarchyAdapter(Behavior.class, new BehaviorAdapter());
gson = builder.create();


Then when i try to serialize my ArrayList:

String json2 = gson.toJson(behaviors);


I get a stack overflow.

It appears that on line:

JsonElement elem = context.serialize(src);


It starts a recursive loop, going again and again through my serializer. So How do i register it so that this won't happen? I need to serialize the list and maintain polymorphism.

Answer

Looks like you found the infinite loop the JsonSerializer docs warn about:

However, you should never invoke it on the src object itself since that will cause an infinite loop (Gson will call your call-back method again).

The easiest way I can think of is to create a new Gson instance that does not have the handler installed, and run your instances through that.

As an end run, you could just serialize the List<Behavior> instead:

public class BehaviorListAdapter implements JsonSerializer<List<Behavior>> {

    private static final String CLASSNAME = "CLASSNAME";
    private static final String INSTANCE = "INSTANCE";

    @Override
    public JsonElement serialize(List<Behavior> src, Type typeOfSrc,
            JsonSerializationContext context) {
        JsonArray array = new JsonArray();
        for (Behavior behavior : src) {
            JsonObject behaviorJson = new JsonObject();
            String className = src.getClass().getCanonicalName();
            behaviorJson.addProperty(CLASSNAME, className);
            JsonElement elem = context.serialize(behavior);
            behaviorJson.add(INSTANCE, elem);
            array.add(behaviorJson);
        }
        return array;
    }
}

GsonBuilder builder = new GsonBuilder();
// use a TypeToken to make a Type instance for a parameterized type
builder.registerTypeAdapter(
    (new TypeToken<List<Behavior>>() {}).getType(),
    new BehaviorListAdapter());
gson = builder.create();
Comments