【问题标题】:Why does Gson.toJson serialize a generic field to an empty JSON object?为什么 Gson.toJson 将通用字段序列化为空 JSON 对象?
【发布时间】:2011-09-04 13:59:52
【问题描述】:

我有一个包含 T 类型字段的泛型类,Gson 将此字段序列化为空对象。我在下面包含了代码来演示这个问题。读回 JSON 似乎没问题(只要您提供正确的类型标记)。

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
    }
}

【问题讨论】:

    标签: java gson


    【解决方案1】:

    来自他们的文档:

    当你调用 toJson(obj) 时,Gson 调用 obj.getClass() 来获取关于要序列化的字段的信息。同样,您通常可以在 fromJson(json, MyClass.class) 方法中传递 MyClass.class 对象。如果对象是非泛型类型,这可以正常工作。但是,如果对象是泛型类型,那么泛型类型信息会因为 Java 类型擦除而丢失

    您可以通过为泛型类型指定正确的参数化类型来解决此问题。您可以使用 TypeToken 类来做到这一点。

    他们为List&lt;T&gt; 提供了以下示例:

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

    所以对于您的代码,您需要...

    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

    【讨论】:

    • 谢谢 - 这确实有效,但似乎与本节相矛盾:sites.google.com/site/gson/… 其中Collection&lt;Integer&gt; 是在没有类型标记的情况下序列化的。您能解释一下我的示例和手册示例之间的区别吗?
    • 我怀疑他们有专门处理集合和数组的代码,但除此之外......不知道。
    • 看起来是这样的。与处理原始对象相比,Java 泛型像往常一样浪费了我更多的时间。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    相关资源
    最近更新 更多