【问题标题】:Using a generic type with Gson在 Gson 中使用泛型类型
【发布时间】:2011-03-20 19:10:54
【问题描述】:

我正在尝试创建一个用于Google Gson 的通用类。我创建了类GsonJsonConverterImplementation<T>。这个类有如下方法:

public T deserialize(String jsonString) {
    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat("MM/dd/yy HH:mm:ss");

    Gson gson = builder.create();
    return gson.fromJson(jsonString, T); // T.class etc. what goes here
}

目标是该方法应该能够与我设置 GsonJsonConverterImplementation 的任何类型一起使用。不幸的是,gson.fromJson(jsonString, T) 不起作用,使用T.class 代替 T 也不起作用。我确信问题源于我对 Java 泛型类型缺乏了解。在 Gson 中使用泛型的正确方法是什么?

编辑
使用Kris's answer 我认为这应该可行。不幸的是,clazz 不能以这种方式使用并导致编译器错误。使用 Gson 处理集合和泛型类型有哪些选择?

public List<T> deserializeList(String jsonString, Class<T> clazz) {
    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat("MM/dd/yy HH:mm:ss");
    Gson gson = builder.create();

    Type listType = new TypeToken<clazz>(){}.getType(); // compiler error

    return gson.fromJson(jsonString, listType);
}

【问题讨论】:

  • 我不知道你是否可以让这个(List -- 可以)与 Gson 一起工作,因为 TypeToken 本质上仍然是一个静态构造(这就是为什么你的代码可以不行)。但是,如果您不是绝对必须使用 Gson,Jackson 确实支持类型的编程创建(通过 TypeFactory 方法)并允许您尝试实现的目标。

标签: java json generics gson


【解决方案1】:

您尝试的最简单方法是定义要在方法签名本身中返回的类的类型。您可以通过将“T”的实例传递给方法或要返回的值的类来实现。在您希望生成返回值的情况下,第二种方法更为典型。以下是使用 Gson 的这种方法的示例:

public <T> T deserialize(String jsonString, Class<T> clazz) {
    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat("MM/dd/yy HH:mm:ss");

    Gson gson = builder.create();
    return gson.fromJson(jsonString, clazz);
}

用法:

MyClass mc = deserialize(jsonString, MyClass.class);

【讨论】:

  • Kris 虽然这行得通,但为类设置泛型类型有什么意义?在我看来,GsonJsonConverterImplementation&lt;T&gt; 应该足够了。我错过了什么?
  • 在我的示例中,除非您在其他地方使用它,否则没有意义。这是泛型的问题之一,也是您看到使用我展示的方法初始化实例而不是在类级别配置泛型类型的框架的主要原因。在大多数情况下,您无法检索和使用在类级别定义的实际通用类类型。因此,您无法使用它来创建新实例或执行需要 Class 实例的任何其他操作。
  • 作为后续,如果您有一个具有 Generic 类型的类的子类,那么有一些方法可以检索该类型,但是该方法也存在问题。这是一个基本示例(从具有通用类型的父类实现)在这种情况下如何检索类实例: (Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0 ]
  • 此外,还有一个名为 ClassMate (github.com/cowtowncoder/java-classmate) 的 Java 库可以可靠地执行此操作:子类化的问题是可靠地解析所有类型变量,因此它适用于任意数量的子类型,一些部分绑定。
  • 在检查了大约 3…5 种不同的实现之后,这个正在运行!谢谢。
【解决方案2】:

要获得List&lt;T&gt; 的运行时类型,给定T 的类,它会很糟糕,因为JDK 认为我们不需要它,所以没有支持。你可以继承ParameterizedType,但这真的很糟糕。

    Type typeListT = new ParameterizedType()
    {
        public Type[] getActualTypeArguments()
        {
            return new Type[]{clazz};
        }
        public Type getRawType()
        {
            return List.class;
        }
        public Type getOwnerType()
        {
            return null;
        }
        public boolean equals(Object obj)
        {
            // must implement equals per spec. this sucks
        }
        public int hashCode()
        {
            // this blows! Java forgot to specific it!
            // since we override equals, we should override hashCode
            // we have no idea what value should be returned here!
            // note we are co-existing with other ParameterizedType impls
        }
    };

【讨论】:

  • 这是一个糟糕的答案,也许您可​​以专注于技术细节而不是抱怨 API 的缺点。就目前而言,我什至看不到您发布的内容如何使用该技术。
【解决方案3】:

我正在使用这些方法使用 GSON 读写 Object。

public static <T> void saveAnyTypeOfObject(String key, T value){
        Gson gson = new Gson();
        String json = gson.toJson(value);
        SharedPref.save(key, json);
    }
    //Type listType = new TypeToken<YourClass>(){}.getType();
    public static <T> T readAnyTypeOfObject(String key, Type tt) {
        Gson gson = new Gson();
        String json = SharedPref.read(key, "{}");
        T obj = gson.fromJson(json, tt);
        return obj;
    }

像这样阅读

  TypeToken<YourClassName> typeToken= new TypeToken<YourClassName>() {};
  YourClassName yourClassName = ListSharedPref.readAnyTypeOfObject("keyForSavingClass", typeToken.getType());

然后像这样保存

YourClassName yourClassName = gson.fromJson(objJsonObject.toString(),YourClassName.class);               
ListSharedPref.saveAnyTypeOfObject("keyForSavingClass",yourClassName);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多