文档章节

Java中泛型集合List<T>反序列化问题及解决方法

留给明天
 留给明天
发布于 2017/06/22 00:26
字数 708
阅读 169
收藏 0
点赞 0
评论 2

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

问题1

有这样两个类:

class MyObj {
    int x;
}

class MyList {
    List<MyObj> 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<MyObj> 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<MyObj> list = new Gson().fromJson("[{x:1}]", ArrayList<MyObj>.class);

更糟糕,连编译都无法通过!因为Java的泛型是用 擦拭法

实现的,说白了只是编译器提供给程序员的语法糖,根本不存在ArrayList<MyObj>这样一个类。那么怎样才能让GSON反序列化出我们想要的泛型对象呢?答案是,请TypeToken帮忙:

@Test
	public void test3() {
		Type type = new TypeToken<ArrayList<MyObj>>() {}.getType();
		ArrayList<MyObj> list = new Gson().fromJson("[{x:1}]", type);
		Assert.assertEquals(1, list.size());
		Assert.assertEquals(MyObj.class, list.get(0).getClass());
	}

GSON提供了 TypeToken 这个类来帮助我们捕获(capture)像ArrayList<MyObj>这样的泛型信息。test3()的第一行代码创建了一个 匿名内部类 ,这样,Java编译器就会把泛型信息编译到这个匿名内部类里,然后在运行时就可以被 getType() 方法用 反射API 提取到。

问题3

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

public static <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {
        Type type = new TypeToken<ArrayList<T>>() {}.getType();
        return new Gson().fromJson(json, type);
    }

这个测试能通过吗?

@Test
    public void test4() {
        ArrayList<MyObj> 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 <T> ArrayList<T> jsonToList(String json, Class<T> classOfT) {
	Type type = new TypeToken<ArrayList<JsonObject>>(){}.getType();
	ArrayList<JsonObject> jsonObjs = new Gson().fromJson(json, type);
	
	ArrayList<T> listOfT = new ArrayList<>();
	for (JsonObject jsonObj : jsonObjs) {
	    listOfT.add(new Gson().fromJson(jsonObj, classOfT));
	}
	
	return listOfT;
    }

分两步,先反序列化出ArrayList<JsonObject>,然后在一个个的把JsonObject转成classOfT类型的对象。

© 著作权归作者所有

共有 人打赏支持
留给明天
粉丝 0
博文 41
码字总数 16679
作品 0
深圳
加载中

评论(2)

留给明天
留给明天

引用来自“窗外有个蓝蓝天”的评论

用TypeToken就行了,匿名内部类可以获取泛型的具体类型
是啊,Gson可以解析带泛型的
窗外有个蓝蓝天
窗外有个蓝蓝天
用TypeToken就行了,匿名内部类可以获取泛型的具体类型
Hibernate反射DAO模式

在持久层框架中,如果我们要像简单的JDBC连接数据库那样写一个通用的Dao方法的话,那么把JDBC简单的业务逻辑搬到hibernate持久层框架中,当然是不可能的,这里主要的问题就在于hibernate持久...

zretc
2013/07/19
0
0
GSON使用笔记(3) -- 如何反序列化出List

GSON使用笔记(3) -- 如何反序列化出List 时间 2014-06-26 17:57:06 CSDN博客原文 http://blog.csdn.net/zxhoo/article/details/34856061 本文通过3个问题来讨论如何使用 GSON 把JSON反序列...

thinkyoung
2015/03/24
0
0
Java编程语言高级特性入门学习——泛型、反射和注解!

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰
06/02
0
0
java基础专栏—Properties

Properties 一个持久的属性集。Properties可以保存在流中或从流中加载,Map中每个键和值都对应字符串 HashTable的子类,Map集合的方法都可以使用,线程安全 该集合没有泛型,且不能写泛型 它...

T-newcomer
2017/10/21
0
0
Java高级特性入门——泛型、反射和注解!

摘要: 只有掌握了Java的高级特性,这门语言才算真正地登堂入室。本文将带领大家一同了解Java语言的三个常用的高级特性——泛型、反射和注解。 专家简介: 澳明 ,阿里巴巴高级开发工程师,来...

Java高级架构
05/28
0
0
Java List序列化的实现

概述 java中的序列化与反序列化都要求对象实现接口(其实就是声明一下),而对于List这种动态改变的集合默认是不实现这个接口的,也就是不能直接序列化。但是数组是可以序列化的,所以我们只...

时刻在奔跑
04/17
0
0
Java高级特性入门——泛型、反射和注解

摘要: 只有掌握了Java的高级特性,这门语言才算真正地登堂入室。本文将带领大家一同了解Java语言的三个常用的高级特性——泛型、反射和注解。 数十款阿里云产品限时折扣中,赶紧点击这里,领...

阿里云云栖社区
05/15
0
0
Kotlin语言中的泛型设计哲学

Kotlin语言的泛型设计很有意思,但并不容易看懂。关于这个部分的官方文档,我反复看了好几次,终于弄明白Kotlin语言泛型设计的背后哲学。这篇文章将讲述Kotlin泛型设计的整个思考过程及其背后...

欧阳锋
04/16
0
0
使用CXF开发RestFul WebService问题解决方案

最近在项目中,因为几个系统自己需要数据交换,所以采用进来都比较流行的RestFul风格WebService,实现框架采用apache的cxf,apache的东西一直以来都是比较的好用,回话少说,进入正题。 首先...

xdev
2013/05/18
0
3
【转】Java语法糖的味道:泛型与类型擦除

泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类...

mj4738
2011/11/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
2
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
1
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
1
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
今天
3
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
1
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
2
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
1
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部