Seephor Seephor - 11 days ago 5
Java Question

How to deserialize nested interface types with Gson

I am trying to get Gson to deserialize a nested object in my JSON into a class that implements an interface.

Here is my interface:

public interface ActivationFunction {

public float activate(float input);

}


I have an implementing class named LinearActivation and a Layer class that has a class variable of type ActivationFunction. Here is my JSON:

{
"layers" : [
{
"input":6,
"output":2,
"weights":[[1,2,3,4,5,6],[7,8,9,10,11,12]],
"function":{"LinearFunction"
}
]
}


I read this post: Polymorphism with gson and I searched Gson docs here: https://github.com/google/gson/blob/master/UserGuide.md#TOC-Writing-a-Deserializer

but I can't find any documentation on creating a typeHierarchyAdapter. I followed the example in the first link, but I am not sure how INSTANCE and CLASSNAME should be used within my JSON structure.

Here is the type hierarchy adapter:

public class ActivationFunctionAdapter implements JsonDeserializer<ActivationFunction> {

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

@Override
public ActivationFunction deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
String className = prim.getAsString();

Class<?> klass = null;
try {
klass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new JsonParseException(e.getMessage());
}
return context.deserialize(jsonObject.get(INSTANCE), klass);
}

}


Any help or guidance would be much appreciated

Answer

I was able to get this to work by following the guide here:

https://futurestud.io/tutorials/how-to-deserialize-a-list-of-polymorphic-objects-with-gson

also same info can be seen in the answer by Perception in this question: Using Gson with Interface Types

Basically just had to add the RuntimeTypeAdapterFactory class to my project, (which the code is available in the extras package in the Gson github), then define a type token and use it. For example:

TypeToken<ActivationFunction> functionTypeToken = new TypeToken<ActivationFunction>() {};

RuntimeTypeAdapterFactory<ActivationFunction> typeFactory = 
RuntimeTypeAdapterFactory.of(ActivationFunction.class, "type")
                         .registerSubtype(LinearFunction.class, "linear");

final Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeFactory).create();
Comments