【问题标题】:ClassCastException with Gson and class inheritance from generic ArrayList带有 Gson 的 ClassCastException 和从通用 ArrayList 的类继承
【发布时间】:2018-03-13 10:49:13
【问题描述】:

我在使用 Gson 解析与 Json 之间的自定义类实例时遇到问题。这是我正在处理的代码的简化版本:

import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.util.ArrayList;
import java.util.Arrays;

class IntegerArrayList extends ArrayList<Integer> {
    public static IntegerArrayList fromJson(String json) {
        TypeToken<IntegerArrayList> integerArrayListTypeToken = new TypeToken<IntegerArrayList>() {} ;
        IntegerArrayList integerArrayList = new GsonBuilder()
                .enableComplexMapKeySerialization()
                .create()
                .fromJson(json, integerArrayListTypeToken.getType());
        return integerArrayList;
    }

    public String toJson() {
        TypeToken<IntegerArrayList> integerArrayListTypeToken = new TypeToken<IntegerArrayList>() {};
        return new GsonBuilder()
                .enableComplexMapKeySerialization()
                .setPrettyPrinting()
                .create()
                .toJson(this, integerArrayListTypeToken.getType());
    }

    public IntegerArrayList(Integer... items) {
        super();
        addAll(Arrays.asList(items));
    }
}

public class GsonTest {
    public static void main(String[] args) {
        IntegerArrayList integerArrayList = new IntegerArrayList(1, 2, 3, 4, 5);
        String json = integerArrayList.toJson();
        IntegerArrayList integerArrayList1 = IntegerArrayList.fromJson(json);
    }
}

我收到此错误:

Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to IntegerArrayList
    at IntegerArrayList.fromJson(GsonTest.java:13)
    at GsonTest.main(GsonTest.java:36)

所以这里的问题是,它不是返回一个 IntegerArrayList 实例,而是返回它继承自的 ArrayList。

有没有机会直接从 Gson 获得 IntegerArrayList?怎么样?

提前非常感谢!

【问题讨论】:

  • 想解释一下否决票?
  • 与此问题无关,但您可以通过调用fromJson(json, IntegerArrayList.class) 来简化fromJson(json, integerArrayListTypeToken.getType());。你打电话给enableComplexMapKeySerialization()有什么原因吗? Gson 默认将 Collections 序列化为 JSON 数组,因此设置不应该有任何影响。

标签: java generics inheritance gson


【解决方案1】:

ClassCastException 是由 bug in Gson 引起的,它会导致它创建标准 JDK 集合实例,即使它们与反序列化类型不兼容。

但是,这里的根本问题(一旦 Gson 错误被修复后仍然存在)是您的 IntegerArrayList 类没有无参数构造函数。因此 Gson 无法创建您的类的实例。您可以通过添加无参数构造函数(IntegerArrayList() { ... },可见性无关紧要)或注册InstanceCreator 来解决此问题。

【讨论】:

    【解决方案2】:

    好的,我刚刚编写了一个自定义适配器,它工作正常。不过,使用真正的代码会稍微复杂一些,但至少我知道该由谁来解决这个问题。

    代码如下:

    import com.google.gson.GsonBuilder;
    import com.google.gson.TypeAdapter;
    import com.google.gson.stream.JsonReader;
    import com.google.gson.stream.JsonWriter;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    
    class IntegerArrayList extends ArrayList<Integer> {
        String customField = "test";
    
        public IntegerArrayList(Integer... items) {
            super();
            addAll(Arrays.asList(items));
        }
    
        public static IntegerArrayList fromJson(String json) {
            IntegerArrayList integerArrayList = new GsonBuilder()
                    .registerTypeAdapter(IntegerArrayList.class, new JsonAdapter())
                    .enableComplexMapKeySerialization()
                    .create()
                    .fromJson(json, IntegerArrayList.class);
            return integerArrayList;
        }
    
        public String toJson() {
            return new GsonBuilder()
                    .registerTypeAdapter(IntegerArrayList.class, new JsonAdapter())
                    .enableComplexMapKeySerialization()
                    .setPrettyPrinting()
                    .create()
                    .toJson(this, IntegerArrayList.class);
        }
    
        public static class JsonAdapter extends TypeAdapter<IntegerArrayList> {
            @Override
            public void write(JsonWriter out, IntegerArrayList value) throws IOException {
                out.beginObject();
                out.name("customField").value(value.customField);
                out.name("items");
                out.beginArray();
                for (Integer v : value) {
                    out.value(v);
                }
                out.endArray();
                out.endObject();
            }
    
            @Override
            public IntegerArrayList read(JsonReader in) throws IOException {
                IntegerArrayList rtn = new IntegerArrayList();
                in.beginObject();
                while (in.hasNext()) {
                    switch (in.nextName()) {
                        case "customField":
                            rtn.customField = in.nextString();
                            break;
                        case "items":
                            in.beginArray();
                            while (in.hasNext()) {
                                rtn.add(in.nextInt());
                            }
                            in.endArray();
                    }
                }
                in.endObject();
                return rtn;
            }
        }
    }
    
    public class GsonTest {
        public static void main(String[] args) {
            IntegerArrayList integerArrayList = new IntegerArrayList(1, 2, 3, 4, 5);
            String json = integerArrayList.toJson();
            IntegerArrayList integerArrayList1 = IntegerArrayList.fromJson(json);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      • 2015-09-27
      • 1970-01-01
      • 2015-05-14
      • 1970-01-01
      • 2015-01-14
      相关资源
      最近更新 更多