如何通过静态实用程序方法正确使用Gson反序列化通用类型的对象? [英] How correctly use Gson to deserialize an object of generic type through a static utility method?

查看:47
本文介绍了如何通过静态实用程序方法正确使用Gson反序列化通用类型的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到了许多其他相似的问题,但是我认为在这些问题上有一定程度的抽象.即,我有一个带有静态通用包装器方法的实用程序类,用于反序列化通用类型的对象(在构建时未知):

I've seen a number of other similar looking questions, but I think there's a level of abstraction on top of those that makes the difference. Namely, I have a utility class with a static generic wrapper method to deserialize an object of generic type (unknown at build time):

public final class Utils {

    public static final Gson sGson = new Gson();

    public static synchronized <T> T fromJson(String doc) {
        return sGson.fromJson(doc, new TypeToken<T>(){}.getType());
    }
}

一个简单的类对其进行测试:

A simple class to test it on:

public class TestDocument {
    public TestDocument(String test) {
        this.test = test;
    }

    public String test;
}

效果很好:

assertEquals(
   new TestDocument("test").test, 
   ((TestDocument) Utils.sGson.fromJson(
                      "{\"test\": \"test\"}", 
                      new TypeToken<TestDocument>(){}.getType())).test);

但是,尽管静态通用实用程序方法没有,但看上去却是等效的调用方式:

But what looks like an equivalent way to call this though the static generic utility method does not:

assertEquals(
   new TestDocument("test").test, 
   Utils.<TestDocument>fromJson("{\"test\": \"test\"}").test);

引发以下异常:

java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap无法转换为TestDocument

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to TestDocument

有没有办法让它通过通用方法工作?

Is there a way to make it work through the generic method?

推荐答案

有一些类型用法提示:

  • 使用< T> 而不传递实际类型是一个骗局,由于泛型类型擦除.
  • 将类型作为 Class< T> 传递不是一个好主意,因为 ###.class 仅表示JVM加载的类(原始类型除外)..这样, Class< List< String>> Class< List< Map< Integer,?>>> 完全相同.class 丢失类型参数,因此使Gson(反)序列化工作时无需考虑适当的类型(例如,如果我记得,LinkedHashTreeMap是一个很好的例子).
  • Gson通常与 Type 一起使用,该类型是Java类型系统可以表示的任何类型(包括类, ParameterizedType 等)的超类型接口.请参见
  • Using <T> without passing an actual type is a hoax due to the generic types erasure.
  • Passing the type as Class<T> is not a very good idea because ###.class merely represents a class loaded by JVM (except the primitive types). Having that, Class<List<String>> and Class<List<Map<Integer, ?>>> are totally the same List.class losing type parameterization therefore making Gson (de)serialize work without proper types in mind (LinkedHashTreeMap, for example, is a good example if I remember).
  • Gson mostly works with Type that is a super type interface for any type that can be represented by the Java type system (including classes, ParameterizedType, etc). See https://google.github.io/gson/apidocs/com/google/gson/Gson.html#fromJson-java.lang.String-java.lang.reflect.Type-
  • TypeToken is a good example of a generic type holder in Java, including it produces proper type information depending on how it was build. It can be used to make your method type safe: public static <T> T fromJson(String doc, TypeToken<? extends T> typeToken) { return sGson.fromJson(doc, typeToken.getType()); }. Type tokens can be cached into public (yes) static final fields holding real parameterization due being immutable and thread-safe across threads.

奖金:

  • 在那里不需要同步: Gson 实例也是线程安全的.
  • No synchronized is necessary there: Gson instances are thread-safe too.

这篇关于如何通过静态实用程序方法正确使用Gson反序列化通用类型的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆