找出GSON的TypeToken是否包含一个列表?

时间:2017-05-08 17:39:20

标签: java json gson

我使用GSON解析Java中的json。当我想从json String获取整数列表时,我的代码可能如下所示:

    Type type = new TypeToken<List<Integer>>(){}.getType();

    List<Integer> result = null;
    try {
        result = new Gson().fromJson(jsonStringGoesHere, type);
    } catch (JsonSyntaxException e) {
        e.printStackTrace();
    }

如果jsonStringGoesHere为空字符串或为null,则result也为空。

虽然集合等于null被认为是不好的做法,所以我希望在这种情况下有一个空的List而不是null。

所以基本上这就是我现在要做的:如果result为空,我想检查typeList(或List的子类型)。如果为true,我将使结果为空ArrayList。如何检查type是否包含ListList的子类型?

我的尝试是检查if(type instanceof Collection) - 但返回false。

我的下一个尝试是取type.getTypeName()返回字符串java.util.List<java.lang.Integer>,并尝试从中创建一个对象:

        Class c = Class.forName(type.getTypeName());
        Object o = c.newInstance();
        if(o instanceof List){
            System.out.println("it's working!");
        }

但这会引发java.lang.ClassNotFoundException: java.util.List<java.lang.Integer>

任何想法如何使这项工作?

2 个答案:

答案 0 :(得分:1)

  

我的尝试是检查if(type instanceof Collection) - 但返回false

这不会起作用,因为TypeCollection不是&#34;可以相互转换&#34;并存在于不同的层次结构中。

  

我的下一次尝试是取type.getTypeName(),返回字符串java.util.List<java.lang.Integer>

这也不会奏效。 Class.forName以完全限定的名称返回现有的Class<?>实例(简单来说,就是.classCLASSPATH文件所代表的内容,但从不 - 参数化类(类不可参数化,但可以是带参数化超类的子类 - 这就是类型标记之下的内容)。因此,Class.forName("java.util.List")是有道理的,但Class.forName("java.util.List<String>")没有。

请注意,Type 可以代表某种类型,而TypeToken<T>可以达到此目的。只要看看它是如何宣布的 - 你就会更好地理解它。更重要的是,它的子接口ParameterizedType可以保存类型参数,这可以通过TypeToken生成或手动构建(像往常一样 - 只需看一下接口声明)。 TypeToken通常使用匿名基类参数化来获取类型参数,以及它们的设计原理:完善的编译时支持+ Google Guava中的类似技术,杰克逊, Spring Framework(但如果Java可以支持类似java.util.List<Integer>.type的东西来获取参数化类型实例,那将会很好)。从后来的Gson版本开始,您甚至可以使用TypeToken.getParameterized(...)来创建参数化类型。

你正在寻找的是一个&#34; class-instanceof&#34;或&#34; a-subclass-of&#34; (如果可以这样称呼它):Class.isAssignableFrom(...)。此实例方法检查一个类是否相同或另一个类的子类。说,

SuperClass.class.isAssignableFrom(SubClass.class)

始终返回true。所以你只需要这样检查:

final Type type = new TypeToken<List<Integer>>() {
}.getType();
final TypeToken<?> typeToken = TypeToken.get(type);
System.out.println(List.class.isAssignableFrom(typeToken.getRawType()));

甚至更短:

final TypeToken<List<Integer>> typeToken = new TypeToken<List<Integer>>() {
};
System.out.println(List.class.isAssignableFrom(typeToken.getRawType()));

两者都返回true。请注意,类型标记通过Class<?>返回getRawType()个实例,但不返回getType(),因为后者可能不代表类(例如Collection<String>.class.isAssignableFrom(List<Integer.class>)会返回什么类型?)

此外,您可以将类型标记及其类型提取到static final字段,因为它们是不可变的值,不应在运行时更改。

答案 1 :(得分:0)

在Java中,通用部分的集合在编译时发挥作用,因此它在运行时不可用,这就是您获得该异常的原因。因此,如果您想使用反射创建集合类,那么您必须删除通用部分。

列表设置地图是他们无法直接实例化的界面。因此,为了创建对象,您必须使用其中一个实现,例如 ArrayList LinkedList 等。