Elye
Elye

Reputation: 60081

Deserializing interface data using gson not getting the value back?

I'm running a simple experiment test below.

public class MyTest {

    @Test
    public void testing() {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(SubData.class, new SubDataImplInstanceCreator());
        Gson gson = builder.create();

        Dataclass data = new Dataclass();
        data.key1 = "abc";
        SubDataImpl subData = new SubDataImpl();
        subData.hello = "ttt";
        data.sub = subData;
        String jsonValue = gson.toJson(data);
        System.out.println(jsonValue);

        Dataclass data2 = gson.fromJson(jsonValue, Dataclass.class);
        System.out.println(gson.toJson(data2));

    }

    class Dataclass implements Serializable {
        String key1;
        SubData sub;
    }

    interface SubData {
        String getHello();
    }

    class SubDataImpl implements SubData, Serializable {

        String hello;

        @Override
        public String getHello() {
            return hello;
        }
    }


    public class SubDataImplInstanceCreator implements InstanceCreator<SubDataImpl> {
        @Override
        public SubDataImpl createInstance(Type type) {
            return new SubDataImpl();
        }
    }
}

I'm expecting it to return

{"key1":"abc","sub":{"hello":"ttt"}}
{"key1":"abc","sub":{"hello":"ttt"}}

As they are essentially the same data that get serialized and deserialized.

However, when I run it, I got

{"key1":"abc","sub":{"hello":"ttt"}}
{"key1":"abc","sub":{}}

Why did I loose away my SubData value, after deserializing the Json String? Did I miss anything in my code?

Upvotes: 2

Views: 589

Answers (2)

Elye
Elye

Reputation: 60081

I'm using the below

public class MyTest {
    @Test
    public void testing() {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(SubData.class, new SubDataTypeAdapter());
        Gson gson = builder.create();

        Dataclass data = new Dataclass();
        data.key1 = "abc";
        SubDataImpl subData = new SubDataImpl();
        subData.hello = "ttt";
        data.sub = subData;
        String jsonValue = gson.toJson(data);
        System.out.println(jsonValue);

        Dataclass data2 = gson.fromJson(jsonValue, Dataclass.class);
        System.out.println(gson.toJson(data2));
    }

    class SubDataTypeAdapter extends TypeAdapter<SubDataImpl> {

        @Override
        public void write(JsonWriter out, final SubDataImpl subData) throws IOException {
            out.beginObject();
            out.name("hello").value(subData.getHello());
            out.endObject();
        }

        @Override
        public SubDataImpl read(JsonReader in) throws IOException {
            final SubDataImpl subData = new SubDataImpl();

            in.beginObject();
            while (in.hasNext()) {
                switch (in.nextName()) {
                    case "hello":
                        subData.hello = in.nextString();
                        break;
                }
            }
            in.endObject();

            return subData;
        }
    }

    class Dataclass implements Serializable {
        String key1;
        SubData sub;
    }

    abstract class SubData {
        abstract String getHello();
    }

    class SubDataImpl extends SubData implements Serializable {

        String hello;

        @Override
        public String getHello() {
            return hello;
        }
    }
}

Upvotes: 0

Yazan Jaber
Yazan Jaber

Reputation: 2068

It seems you have hit this bug , the suggested solution is to use a TypeAdapter for the interface.

Quick and dirty implementation (use it in place ofSubDataImplInstanceTypeAdapter)

 public class SubDataImplInstanceTypeAdapter implements JsonDeserializer<SubDataImpl>, JsonSerializer<SubDataImpl> {


    @Override
    public SubDataImpl deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        SubDataImpl impl = new SubDataImpl();
        JsonObject object = json.getAsJsonObject();
        impl.setHello(object.get("hello").getAsString());
        return impl;

    }

    @Override
    public JsonElement serialize(SubDataImpl src, Type typeOfSrc, JsonSerializationContext context) {
        return context.serialize(src);
    }
}

Upvotes: 2

Related Questions