Json: Deserializing Interface class with List of Interface generic type

Viewed 1501

I serialize a subclasses of UserInterface type based on type of user. Those subclasses have List. Role is an interface as well. I have wrote custom Gson Adapter:

public class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
    final JsonObject wrapper = new JsonObject();
    wrapper.addProperty("type", object.getClass().getName());
    wrapper.add("data", context.serialize(object));
    return wrapper;
}

public T deserialize(JsonElement elem, Type interfaceType, JsonDeserializationContext context) throws JsonParseException {
    final JsonObject wrapper = (JsonObject) elem;
    final JsonElement typeName = get(wrapper, "type");
    final JsonElement data = get(wrapper, "data");
    final Type actualType = typeForName(typeName);
    return context.deserialize(data, actualType);
}

private Type typeForName(final JsonElement typeElem) {
    try {
        return Class.forName(typeElem.getAsString());
    } catch (ClassNotFoundException e) {
        throw new JsonParseException(e);
    }
}

private JsonElement get(final JsonObject wrapper, String memberName) {
    final JsonElement elem = wrapper.get(memberName);
    if (elem == null) throw new JsonParseException("no '" + memberName + "' member found in what was expected to be an interface wrapper");
    return elem;
}
}

The problem, however is that I get error: Caused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: Domain.Users.role.Role. I know whats the problem. Gson does not know what concrete implementation to choose for instantiation. How can I tell Gson which class to instantiate?

Here is full stacktrace:

FATAL EXCEPTION: main
                                                               Process: org.ucomplex.ucomplex, PID: 346
                                                               java.lang.RuntimeException: Unable to create application org.ucomplex.ucomplex.Common.base.UCApplication: java.lang.RuntimeException: Unable to invoke no-args constructor for ? extends org.ucomplex.ucomplex.Domain.Users.role.Role. Register an InstanceCreator with Gson for this type may fix this problem.
                                                                   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4729)
                                                                   at android.app.ActivityThread.access$1600(ActivityThread.java:153)
                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412)
                                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                   at android.os.Looper.loop(Looper.java:148)
                                                                   at android.app.ActivityThread.main(ActivityThread.java:5442)
                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
                                                                Caused by: java.lang.RuntimeException: Unable to invoke no-args constructor for ? extends org.ucomplex.ucomplex.Domain.Users.role.Role. Register an InstanceCreator with Gson for this type may fix this problem.
                                                                   at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:226)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210)
                                                                   at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
                                                                   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
                                                                   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:887)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:952)
                                                                   at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162)
                                                                   at org.ucomplex.ucomplex.Domain.Users.InterfaceAdapter.deserialize(InterfaceAdapter.java:36)
                                                                   at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:887)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:852)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:801)
                                                                   at com.google.gson.Gson.fromJson(Gson.java:773)
                                                                   at org.ucomplex.ucomplex.Common.FacadePreferences.getUserDataFromPref(FacadePreferences.java:49)
                                                                   at org.ucomplex.ucomplex.Common.base.UCApplication.onCreate(UCApplication.java:52)
                                                                   at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1014)
                                                                   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4726)
                                                                   at android.app.ActivityThread.access$1600(ActivityThread.java:153) 
                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412) 
                                                                   at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                   at android.os.Looper.loop(Looper.java:148) 
                                                                   at android.app.ActivityThread.main(ActivityThread.java:5442) 
                                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738) 
                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628) 
                                                                Caused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: org.ucomplex.ucomplex.Domain.Users.role.Role
                                                                   at com.google.gson.internal.UnsafeAllocator.assertInstantiable(UnsafeAllocator.java:117)
                                                                   at com.google.gson.internal.UnsafeAllocator.access$000(UnsafeAllocator.java:31)
                                                                   at com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:49)
                                                                   at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223)
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210) 
                                                                   at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 
                                                                   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
                                                                   at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129) 
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220) 
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129) 
                                                                   at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:887) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:952) 
                                                                   at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.deserialize(TreeTypeAdapter.java:162) 
                                                                   at org.ucomplex.ucomplex.Domain.Users.InterfaceAdapter.deserialize(InterfaceAdapter.java:36) 
                                                                   at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:887) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:852) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:801) 
                                                                   at com.google.gson.Gson.fromJson(Gson.java:773) 
                                                                   at org.ucomplex.ucomplex.Common.FacadePreferences.getUserDataFromPref(FacadePreferences.java:49) 
                                                                   at org.ucomplex.ucomplex.Common.base.UCApplication.onCreate(UCApplication.java:52) 
                                                                   at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1014) 
                                                                   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4726) 
                                                                   at android.app.ActivityThread.access$1600(ActivityThread.java:153) 
                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412) 
                                                                   at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                   at android.os.Looper.loop(Looper.java:148) 
                                                                   at android.app.ActivityThread.main(ActivityThread.java:5442) 
                                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738) 
                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628) 

EDIT: This question got marked as duplicate. However, the marked question answers how to deserialize Interface type (and not in the smartest way). My problem is not in that. I know how to deserialize top level interface type. In my case I have Base implementation of the interface that has a List of another interface type. This class is used for composition. Picture this:

interface IA {}

interface IR {}

class R1 implements IR {}

class R2 implements IR {}

class A1 implements IA {
    private List<IR> list;
}

class A2 implements IA {
    private A1 member;
}

class A3 implements IA {
    private A1 member;
}

Problem arises while deserilizing private List<IR> list;.

1 Answers
Related