Why does Gson.toJson serialize a common field to an empty JSON object?

I have a generic class containing a field of type T, Gson serializes this field as an empty object. I have provided the code below to demonstrate this problem. Reading JSON backwards seems fine (as long as you supply the correct type token).

import java.lang.reflect.Type; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; public class GsonIssue { static class AbstractThing { private String fieldA = "valueA"; public String getFieldA() { return fieldA; } public void setFieldA(String fieldA) { this.fieldA = fieldA; } @Override public String toString() { return "AbstractThing [fieldA=" + fieldA + "]"; } } static class Thing extends AbstractThing { private String fieldB = "valueB"; @Override public String toString() { return "Thing [fieldB=" + fieldB + ", fieldA=" + getFieldA() + "]"; } } static class Wrapper<T extends AbstractThing> { private T abstractThing; private String standardField = "standard value"; public Wrapper(T abstractThing) { this.abstractThing = abstractThing; } @Override public String toString() { return "Wrapper [abstractThing=" + abstractThing + ", standardField=" + standardField + "]"; } } public static void main(String[] args) { Wrapper<Thing> wrapper = new Wrapper<Thing>(new Thing()); Gson gson = new Gson(); String json = gson.toJson(wrapper); System.out.println(json); // prints : {"abstractThing":{},"standardField":"standard value"} // so standardField is correctly serialized but not abstractThing. // but if we manually construct the expected json string, and parse it back, we get the expected object structure json = "{\"standardField\": \"some text\", " + "\"abstractThing\":{\"fieldB\" : \"arb value\", \"fieldA\" : \"another arb value\"}}"; Type type = new TypeToken<Wrapper<Thing>>() {}.getType(); Object fromJson = gson.fromJson(json, type); System.out.println(fromJson); // prints : Wrapper [abstractThing=Thing [fieldB=arb value, fieldA=another arb value], standardField=some text] // which is as expected } } 
+6
source share
1 answer

From your documents:

When you call toJson (obj), Gson calls obj.getClass () to get the field information for serialization. Similarly, you can pass the MyClass.class object in the fromJson method (json, MyClass.class). This works fine if the object is not a generic type. However, if the object is of a common type, Generic type information is lost due to Java Type Erasure

You can solve this problem by specifying the correct parameterized type for your generic type. You can do this using the TypeToken class.

They give the following example for List<T> :

 Type listType = new TypeToken<List<String>>() {}.getType(); gson.toJson(myStrings, listType); 

So, for your code you will need ...

 Type myType = new TypeToken<Wrapper<Thing>>() {}.getType(); String json = gson.toJson(wrapper, myType); 

https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener

+8
source

Source: https://habr.com/ru/post/896589/


All Articles