设为首页 加入收藏

TOP

GSON使用笔记(3) -- 如何反序列化出List
2015-07-24 05:51:45 来源: 作者: 【 】 浏览:4
Tags:GSON 使用 笔记 如何 序列化 List

本文通过3个问题来讨论如何使用GSON把JSON反序列化为List。

问题1

有这样两个类:

class MyObj {
    int x;
}

class MyList {
    List
  
    objList = new LinkedList<>();
}
  
那下面的测试能通过吗?

    @Test
    public void test1() {
        MyList myList = new Gson().fromJson("{objList:[]}", MyList.class);
        Assert.assertEquals(LinkedList.class, myList.objList.getClass());
    }

答案1

答案是,测试通不过!原因是GSON不知道objList的具体类型,因此只能选择默认的ArrayList。更详细的解释,可以参考这篇文章和ConstructorConstructor类的源代码。如果确实想让GSON创建LinkedList实例该怎么办呢?也简单,就是给objList一个更具体的类型:

class MyList {
    LinkedList
  
    objList = new LinkedList<>();
}
  

问题2

下面的测试能通过吗?

    @Test
    public void test2() {
        ArrayList
   list = new Gson().fromJson("[{x:1}]", ArrayList.class);
        Assert.assertEquals(1, list.size());
        Assert.assertEquals(MyObj.class, list.get(0).getClass());
    }

答案2

很明显,不能。因为fromJson方法不能从"[{x:1}]"参数推测出数组里放的是MyObj类型的对象,也无法从ArrayList.class参数得到这个信息。那么改成下面这样呢?

ArrayList
  
    list = new Gson().fromJson("[{x:1}]", ArrayList
   
    .class);
   
  
更糟糕,连编译都无法通过!因为 Java的泛型是用 擦拭法实现的,说白了只是编译器提供给程序员的语法糖,根本不存在ArrayList 这样一个类。那么怎样才能让GSON反序列化出我们想要的泛型对象呢?答案是,请TypeToken帮忙:

    @Test
    public void test3() {
        Type type = new TypeToken
   
    >() {}.getType();
        ArrayList
    
      list = new Gson().fromJson("[{x:1}]", type); Assert.assertEquals(1, list.size()); Assert.assertEquals(MyObj.class, list.get(0).getClass()); }
    
   
GSON提供了 TypeToken这个类来帮助我们捕获(capture)像ArrayList 这样的泛型信息。test3()的第一行代码创建了一个 匿名内部类,这样,Java编译器就会把泛型信息编译到这个匿名内部类里,然后在运行时就可以被 getType()方法用 反射API提取到。

问题3

如果我想写一个通用的方法,把json反序列化成List,下面这个方法可行吗?

    public static 
    
      ArrayList
     
       jsonToList(String json, Class
      
        classOfT) { Type type = new TypeToken
       
        >() {}.getType(); return new Gson().fromJson(json, type); }
       
      
     
    
这个测试能通过吗?

    @Test
    public void test4() {
        ArrayList
    
      list = jsonToList("[{x:1}]", MyObj.class);
        Assert.assertEquals(1, list.size());
        Assert.assertEquals(MyObj.class, list.get(0).getClass());
    }
    

答案3

答案是,方法不可行(虽然能编译通过),测试通不过!还是因为Java泛型的擦除法,详细的回答可以看stackoverflow上的这个问题。那还有办法实现jsonToList()这个通用方法呢?有的,只是稍微复杂一点:

    public static 
    
      ArrayList
     
       jsonToList(String json, Class
      
        classOfT) { Type type = new TypeToken
       
        >(){}.getType(); ArrayList
        
          jsonObjs = new Gson().fromJson(json, type); ArrayList
         
           listOfT = new ArrayList<>(); for (JsonObject jsonObj : jsonObjs) { listOfT.add(new Gson().fromJson(jsonObj, classOfT)); } return listOfT; }
         
        
       
      
     
    
分两步,先反序列化出ArrayList ,然后在一个个的把JsonObject转成classOfT类型的对象。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇POJ 2892 Tunnel Warfare (树状数.. 下一篇相见恨晚--Socket通信

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: