qq飞车手机版下载。。。。

Fastjson反序列化泛型类型时候的一个问题 - 田麦 - ITeye技术网站
博客分类:
import static org.junit.Assert.assertF
import static org.junit.Assert.assertT
import java.util.ArrayL
import java.util.L
import org.junit.T
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONA
import com.alibaba.fastjson.TypeR
public class GenericTypeTest {
static class Foo&T&{
public T getT() {
public void setT(T t) {
public void test_FirstWithClass() {
Foo&List&Integer&& foo = new Foo&List&Integer&&();
List&Integer& list = new ArrayList&Integer&();
list.add(3);
foo.setT(list);
String v = JSON.toJSONString(foo);
System.out.println(v);
//parse with class
Foo&?& rst = JSON.parseObject(v, foo.getClass());
assertTrue(rst.getT() instanceof JSONArray);
//parse with TypeReference
rst = JSON.parseObject(v,new TypeReference&Foo&List&Integer&&&(){});
assertTrue(rst.getT() instanceof JSONArray);//这里没有失败
// @Test//此用例跟上边那个不能同时跑,要不然上边跑过之后下边就跑不通了
public void test_FirstWithTypeReference() {
Foo&List&Integer&& foo = new Foo&List&Integer&&();
List&Integer& list = new ArrayList&Integer&();
list.add(3);
foo.setT(list);
String v = JSON.toJSONString(foo);
System.out.println(v);
//parse with TypeReference
Foo&?& rst = JSON.parseObject(v,new TypeReference&Foo&List&Integer&&&(){});
assertFalse(rst.getT() instanceof JSONArray);
文字描述的话就是:
泛型类型反序列化调用paseObject的时候,第一次parseObject传Class,后边传TypeReference或者Type就解析不出泛型类型了,泛型对应的类型只能解析成JsonObject
版本1.2.4及以前,可以解析泛型的版本,应该都有。暂时可以通过含泛型的对象反序列化的时候,只通过传入Type或者TypeReference类型来实现。
浏览 14824
yueyemaitian
浏览: 193960 次
来自: 杭州
你这么牛逼,你父母知道吗
谢楼主,构建成功了
?????
walle1027 写道学习了,正式想要的【问底】静行:FastJSON实现详解
发表于 11:38|
摘要:“快”作为程序员追逐的终极目标之一,而FastJSON则很好的证明了这一特性。本期《问底》,静行将带大家见证它序列化和反序列化的实现过程,一起领略它的“快”感。
还记得电影《功夫》中火云邪神的一句话:天下功夫,无坚不破,唯快不破。在程序员的世界中,“快”一直是大家苦苦修炼,竞相追逐的终极目标之一,甚至到了“不择手段”、“锱铢必较”的地步。
一直使用json游离于各种编程语言和系统之间。一个偶然的机会碰到了Fastjson,被他的无依赖、易使用、应用广等特性深深吸引的同时,更被他出奇的“快”所震惊,在java界犹如一骑绝尘,旁人只能望其项背。很自然的一个想法涌上心头:FastJSON为何如此之快?于是定神来拔一拔其实现,一则膜拜大师的杰作,二则虚心偷技,三则方便来者学习。
本篇接下来的内容是基于FastJSON 1.1.40,着重讲述其序列化、反序列化实现,最后分析FastJSON为何如此“fast”的原因。
所谓序列化,就是将java各种对象转化为json串。不多说,先上图。
&序列化入口
平常我们经常用到的是JSON.toJSONString()这个静态方法来实现序列化。其实JSON是一个抽象类,该类实现了JSONAware(转为json串)和JSONStreamAware(将json串写入Appendable中)的接口,同时又是JSONArray(内部实现就是个List)和JSONObject(内部实现就是个Map)的父类。JSON.toJSONString()方法内部实现基本相同,为做某些特定配置,对外暴露的接口可能不同。该方法的实现实际托付给了JSONSerializer类。
序列化组合器
JSONSerializer类相当于一个序列化组合器,它将上层调用、序列化配置、具体类型序列化实现、序列化字符串拼接等功能组合在一起,方便外部统一调用。该类有几个重要的成员,SerializeConfig、SerializeWriter、各种Filter列表、DateFormat、SerialContext等,还有每次对各个具体对象序列化的ObjectSerializer(非JSONSerializer的成员变量)。下面就来挨个说明其各自功能。
SerializeConfig
SerializeConfig是全局唯一的,它继承自IdentityHashMap,IdentityHashMap是一个长度默认为1024的Hash桶,每个桶存放相同Hash的Entry(可看做链表节点,包含key、value、next指针、hash值)做成的单向链表,IdentityHashMap实现了HashMap的功能,但能避免HashMap并发时的死循环。
SerializeConfig的主要功能是配置并记录每种Java类型对应的序列化类(ObjectSerializer接口的实现类),比如Boolean.class使用BooleanCodec(看命名就知道该类将序列化和反序列化实现写到一起了)作为序列化实现类,float[].class使用FloatArraySerializer作为序列化实现类。这些序列化实现类,有的是FastJSON中默认实现的(比如Java基本类),有的是通过ASM框架生成的(比如用户自定义类),有的甚至是用户自定义的序列化类(比如Date类型框架默认实现是转为毫秒,应用需要转为秒)。当然,这就涉及到是使用ASM生成序列化类还是使用JavaBean的序列化类类序列化的问题,这里判断根据就是是否Android环境(环境变量"java.vm.name"为"dalvik"或"lemur"就是Android环境),但判断不仅这里一处,后续还有更具体的判断。
SerializeWriter
SerializeWriter继承自Java的Writer,其实就是个转为FastJSON而生的StringBuilder,完成高性能的字符串拼接。该类成员如下:
char buf[]
&可理解为每次序列化后字符串的内存存放地址。
static ThreadLocal& bufLocal&
每次序列化,都需要重新分配buf[]内存空间。而bufLocal就是每次序列化后bug[]的内存空间保留到ThreadLocal里,但其中的值清空,避免频繁的内存分配和gc。
int features&生成json字符串的特征配置,默认配置为:&
&span&QuoteFieldNames | SkipTransientField | WriteEnumUsingToString | SortField&/span&&表示含义为:双引号filedName and 忽略transientField and enum类型使用String写入 and 排序输出field。&支持的所有特征在SerializerFeature类中,用户可在调用时显示配置,也可通过JSONFiled或JSONType注入配置。
Writer&writer&用户指定将生成的json串直接写入某writer中,比如JSONWriter类。
举个例子吧,writeStringWithDoubleQuote()表示用字符串用双引号写入,看看如何拼接字符串的。
Filter列表
SerializeWriter中有很多Filter列表,可视为在生成json串的各阶段、各地方定制序列化,大致如下:
BeforeFilter :序列化时在最前面添加内容
AfterFilter :序列化时在最后面添加内容
PropertyFilter :根据PropertyName和PropertyValue来判断是否序列化
ValueFilter :修改Value
NameFilter :修改key
PropertyPreFilter :根据PropertyName判断是否序列化
DateFormat
指定日期格式。若不指定,FastJSON会自动识别如下日期格式:
ISO-8601日期格式
yyyy-MM-dd
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd HH:mm:ss.SSS
毫秒字符串
.Net Json日期格式
new Date()
SerialContext
序列化上下文,在引用或循环引用中使用,该值会放入references的Hash桶(IdentityHashMap)缓存。
ObjectSerializer&&
ObjectSerializer只有一个接口方法,如下:
void write(JSONSerializer serializer,Objectobject,Object
fieldName,Type fieldType);
可见,将JSONSerializer传入了ObjectSerializer中,而JSONSerializer有SerializeWriter成员,在每个具体ObjectSerializer实现中,直接使用SerializeWriter拼接字符串即可;Object即是待序列化的对象;fieldName则主要用于组合类引用时设置序列化上下文;而fieldType主要是为了泛型处理。
JSONSerializer中通过public ObjectSerializer getObjectWriter(Class clazz)函数获取类对应的序列化类(即实现ObjectSerializer接口的类),大致逻辑如下:
整个过程是先获取已实现基础类对应的序列化类,再通过类加载器获取自定义的AutowiredObjectSerializer序列化类,最后获取通过createJavaBeanSerializer()创建的序列化类。通过该方法会获取两种序列化类,一种是直接的JavaBeanSerializer(根据类的get方法、public
filed等JavaBean特征序列化),另一种是createASMSerializer(通过ASM框架生成的序列化字节码),优先使用第二种。选择JavaBeanSerializer的条件为:
该clazz为非public类
该clazz的类加载器在ASMClassLoader的外部,或者clazz就是 Serializable.class,或者clazz就是Object.class
JSONType的注解指明不适用ASM
createASMSerializer加载失败&
结合前面的讨论,可以得出使用ASM的条件:非Android系统、非基础类、非自定义的AutowiredObjectSerializer、非以上所列的使用JavaBeanSerializer条件。&
具体基础类的序列化方法、JavaBeanSerializer的序列化方法和ASM生成的序列化方法可以参见代码,这里就不做一一讲解了。
2. 反序列化
所谓反序列化,就是将json串转化为对应的java对象。还是先上图。
同样是JSON类作为反序列化入口,实现了parse()、parseObject()、parseArray()等将json串转换为java对象的静态方法。这些方法的实现,实际托付给了DefaultJSONParser类。
DefaultJSONParser类相当于序列化的JSONSerializer类,是个功能组合器,它将上层调用、反序列化配置、反序列化实现、词法解析等功能组合在一起,相当于设计模式中的外观模式,供外部统一调用。同样,我们来分析该类的几个重要成员,看看他是如何实现纷繁的反序列化功能的。
1.& ParserConfig
同SerializeConfig,该类也是全局唯一的解析配置,其中的boolean asmEnable同样判断是否为Andriod环境。与SerializeConfig不同的是,配置类和对应反序列类的IdentityHashMap是该类的私有成员,构造函数的时候就将基础反序列化类加载进入IdentityHashMap中。
2.& JSONLexer&
JSONLexer是个接口类,定义了各种当前状态和操作接口。JSONLexerBase是对JSONLexer实现的抽象类,类似于序列化的SerializeWriter类,专门解析json字符串,并做了很多优化。实际使用的是JSONLexerBase的两个子类JSONScanner和JSONLexerBase,前者是对整个字符串的反序列化,后者是接Reader直接序列化。简析JSONLexerBase的某些成员:
由于json串具有一定格式,字符串会根据某些特定的字符来自解释所表示的意义,那么这些特定的字符或所处位置的字符在FastJSON中就叫一个token,比如"(","{","[",",",":",key,value等,这些都定义在JSONToken类中。
char[] sbuf
解析器通过扫描输入字符串,将匹配得到的最细粒度的key、value会放到sbuf中。
static ThreadLocal& SBUF_REF_LOCAL
上面sbuf的空间不释放,在下次需要的时候直接拿出来使用,从避免的内存的频繁分配和gc。
反序列化特性的配置,同序列化的feature是通过int的位或来实现其特性开启还是关闭的。默认配置是:
AutoCloseSource | UseBigDecimal | AllowUnQuotedFieldNames | AllowSingleQuotes |
AllowArbitraryCommas | AllowArbitraryCommas | SortFeidFastMatch |
IgnoreNotMatch ,表示检查json串的完整性 and 转换数值使用BigDecimal and 允许接受不使用引号的filedName and 允许接受使用单引号的key和value and 允许接受连续多个","的json串 and 使用排序后的field做快速匹配 and 忽略不匹配的key/value对。当然,这些参数也是可以通过其他途径配置的。
hasSpecial
对转义符的处理,比如'\0','\'等。
词法解析器是基于预测的算法从左到右一次遍历的。由于json串具有自身的特点,比如为key的token后最有可能是":",":"之后可能是value的token或为"{"的token或为"["的token等等,从而可以根据前一个token预判下一个token的可能,进而得知每个token的含义。分辨出各个token后,就可以获取具体值了,比如scanString获取key值,scanFieldString根据fieldName获取fieldValue,scanTrue获取java的true等等。其中,一般会对key进行缓存,放入SymbolTable(类似于IdentityHashMap)中,猜想这样做的目的是:应用解析的json串一般key就那么多,每次生成开销太多,干脆缓存着,用的就是就来取,还是空间换时间的技巧。
3.& List& ExtraTypeProvider &和List& ExtraProcessor
视为对其他类型的处理和其他自定义处理而留的口子,用户可以自己实现对应接口即可。
4.& DateFormat
同序列化的DateFormat,不多说了。
5.& ParseContext 和 List& ResolveTask &
ParseContext同序列化的SerialContext,为引用甚至循环引用做准备。 &&
List& ResolveTask &当然就是处理这种多层次甚至多重引用记录的list了。
6.& SymbolTable
上面提到的key缓存。
7.& ObjectDeserializer
跟ObjectSerializer也是相似的。先根据fieldType获取已缓存的解析器,如果没有则根据fieldClass获取已缓存的解析器,否则根据注解的JSONType获取解析器,否则通过当前线程加载器加载的AutowiredObjectDeserializer查找解析器,否则判断是否为几种常用泛型(比如Collection、Map等),最后通过createJavaBeanDeserializer来创建对应的解析器。当然,这里又分为JavaBeanDeserializer和asmFactory.createJavaBeanDeserializer两种。使用asm的条件如下:
非Android系统
该类及其除Object之外的所有父类为是public的
泛型参数非空
非asmFactory加载器之外的加载器加载的类
类的setter函数不大于200
类有默认构造函数
类不能含有仅有getter的filed
类不能含有非public的field
类不能含有非静态的成员类
类本身不是非静态的成员类
使用ASM生成的反序列化器具有较高的反序列化性能,比如对排序的json串可按顺序匹配解析,从而减少读取的token数,但如上要求也是蛮严格的。综上,FastJSON反序列化也支持基础反序列化器、JavaBeanDeserializer反序列化器和ASM构造的反序列化器,这里也不做一一讲解了。
3. Why So Fast
FastJSON真的很快,读后受益匪浅。个人总结了下快的原因(不一定完整):
1.& 专业的心做专业的事
不论是序列化还是反序列化,FastJSON针对每种类型都有与之对应的序列化和反序列化方法,就针对这种类型来做,优化性能自然更具针对性。自编符合json的SerializeWriter和JSONLexer,就连ASM框架也给简化掉了,只保留所需部分。不得不叹其用心良苦。
2.& 无处不在的缓存
空间换时间的想法为程序员屡试不爽,而作者将该方法用到任何细微之处:类对应的序列化器/反序列化器全部存起来,方便取用;解析的key存起来,表面重复内存分配等等。
3.& 不厌其烦的重复代码
我不知道是否作者故意为之,程序中出现了很多类似的代码,比如特殊字符处理、不同函数对相同token的处理等。这样虽对于程序员寻求规整相违背,不过二进制代码却很喜欢,无形之中减少了许多函数调用。
4.& 不走寻常路
对于JavaBean,可以通过发射实现序列化和反序列化(FastJSON已有实现),但默认使用的是ASM框架生成对应字节码。为了性能,无所不用其极。
5.& 一点点改变有很大的差别
排序对输出仅是一点小小的改变,丝毫不影响json的使用,但却被作者用在了解析的快速匹配上,而不用挨个拎出key。
6.& 从规律中找性能
上面也讲到,FastJSON读取token基于预测的。json串自身的规律性被作者逮个正着,预测下一个将出现的token处理比迷迷糊糊拿到一个token再分情况处理更快捷。
不喜欢虎头蛇尾的结局。不过写到这里,除了承认自己对FastJSON代码某些地方还没看懂或理解有偏颇之外,不敢说太多了。关于作者:阿里巴巴集团CDO数据开发平台高级工程师,2010年加入阿里巴巴,长期从事各存储系统(mysql、oracle、odps、hadoop、sqlserver、rds、drds、hbase、oceanbase、db2、ots、tair等)间实时和离线的数据同步工作,打造阿里巴巴云上云下的数据同步通道。
更多《问底》内容
《问底》是CSDN云计算频道新建栏目,以实践为本,分享个人对于新时代软件架构与研发的深刻见解。在含有“【问底】”字样标题的文章中,你会看到某个国外IT巨头的架构分享,会看到国内资深工程师对某个技术的实践总结,更会看到一系列关于某个新技术的探索。《问底》邀请对技术具有独特/深刻见解的你一起打造一片只属于技术的天空,详情可邮件至。
免费订阅“CSDN云计算(左)和CSDN大数据(右)”微信公众号,实时掌握第一手云中消息,了解最新的大数据进展!
CSDN发布虚拟化、Docker、OpenStack、CloudStack、数据中心等相关云计算资讯, & & 分享Hadoop、Spark、NoSQL/NewSQL、HBase、Impala、内存计算、流计算、机器学习和智能算法等相关大数据观点,提供云计算和大数据技术、平台、实践和产业信息等服务。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章活用fastjson序列化和反序列化含枚举类型java对象
活用fastjson序列化和反序列化含枚举类型java对象
来源:极客头条
在使用fastjson对java对象进行序列化和反序列化时,如果含有枚举类型,默认会根据枚举变量的ordinal值进行反序列且序列化时显示枚举字面代表的字符串。经常这种行为不是我们想要的,那么如何进行定制化枚举类型的序列化和反序列? 举例如下
假设待序列化和反序列化java对象结构如下
public class Msg {
private StatusCodeE
public int getId() {
public void setId(int id) {
public StatusCodeEnum getStatus() {
public void setStatus(StatusCodeEnum status) {
this.status =
public static enum StatusCodeEnum {
OK(200, ), SERVER_ERROR(500, );
private static final Map&Integer, StatusCodeEnum& CODE_MAP = new HashMap&Integer, StatusCodeEnum&();
for (StatusCodeEnum typeEnum : StatusCodeEnum.values()) {
CODE_MAP.put(typeEnum.getCode(), typeEnum);
StatusCodeEnum(int code, String meaning) {
this.code =
this.meaning =
public int getCode() {
public String getMeaning() {
public static StatusCodeEnum getEnum(Integer code) {
return CODE_MAP.get(code);
private final S
对象内部定义了状态码枚举类StatusCodeEnum,包含两个实例OK、SERVER_ERROR。
反序列化问题
如何使用fastjson成功反序列如下json串?
{“id”:1,”status”:200}
显然,如果直接用Json.parseObject()方法进行反序列化,会报如下错误信息:
Exception in thread “main” com.alibaba.fastjson.JSONException: parse
enum com.netwaymedia.mon.dto.Msg$StatusCodeEnum
error, value : 200
com.alibaba.fastjson.parser.deserializer.EnumDeserializer.deserialze(EnumDeserializer.java:48)
com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:33)
原因分析:前面已经提过,fastjson默认使用ordinal值去查找对应的枚举实例,显示是获取不到的,所以抛出异常,需要修改status值为0才运行OK。
序列化问题
如果使用JSON.toJSONString()方法对上述Msg对象进行序列化,会得到如下json串
{“id”:1,”status”:”OK”}
显示不是我们所期待的原始字符串
{“id”:1,”status”:200}
如何解决上述两大问题?
优雅的解决方案
答案就在于fastjson提供注解JSONField。通过JSONField可灵活控制字段的序列化和反序列,重新修改Msg结构如下:
public class Msg {
private StatusCodeEnum statusC
public int getId() {
public void setId(int id) {
@JSONField(name = )
public int getStatus() {
return statusCode.getCode();
@JSONField(name = )
public void setStatus(int code) {
this.statusCode = StatusCodeEnum.getEnum(code);
@JSONField(serialize = false)
public StatusCodeEnum getStatusCode() {
return statusC
@JSONField(deserialize = false)
public void setStatusCode(StatusCodeEnum statusCode) {
this.statusCode = statusC
public static enum StatusCodeEnum {
OK(200, ), BAD_REQUEST(400, );
private static final Map&Integer, StatusCodeEnum& CODE_MAP = new HashMap&Integer, StatusCodeEnum&();
for (StatusCodeEnum typeEnum : StatusCodeEnum.values()) {
CODE_MAP.put(typeEnum.getCode(), typeEnum);
StatusCodeEnum(int code, String meaning) {
this.code =
this.meaning =
public int getCode() {
public String getMeaning() {
public static StatusCodeEnum getEnum(Integer code) {
return CODE_MAP.get(code);
private final S
思路是通过修改字段名为statusCod
思路是通过修改字段名为statusCode,并用JSONField注解该字段不进行序列和反序列化,但是提供getStatus/setStatus方法来定制化枚举变量statusCode的序列和反序列,完美的解决前面提到的两大问题。
即使是一小步也想与你分享fastjson对Date的处理 - 野猪林 - ITeye技术网站
博客分类:
对日期的序列化:
一种方法是通过注解
@JSONField (format="yyyy-MM-dd HH:mm:ss")
另一种是通过SerializeConfig:
private static SerializeConfig mapping = new SerializeConfig();
private static String dateF
dateFormat = "yyyy-MM-dd HH:mm:ss";
mapping.put(Date.class, new SimpleDateFormatSerializer(dateFormat));
json字符串中使用单引号:
String text = JSON.toJSONString(object, SerializerFeature.UseSingleQuotes);
字段显示不同的key:
public class User {
@JSONField(name="ID")
public int getId() { ... }
User user = ...;
JSON.toJSONString(user); // {"ID":001}
类的反序列化 JavaBean:
String text = ...; // {"r":255,"g":0,"b":0,"alpha":255}
Color color = JSON.parseObject(text, Color.class);
String text = ...; // [{ ... }, { ... }]
List&User& users = JSON.parseArray(text, User.class);
String text = ...; // {"name":{"name":"ljw",age:18}}
Map&String, User& userMap = JSON.parseObject(text, new TypeReference&Map&String, User&&() {});
自定义序列化代码示例:
public class JsonUtil {
private static SerializeConfig mapping = new SerializeConfig();
private static String dateF
dateFormat = "yyyy-MM-dd HH:mm:ss";
* 默认的处理时间
* @param jsonText
public static String toJSON(Object jsonText) {
return JSON.toJSONString(jsonText,
SerializerFeature.WriteDateUseDateFormat);
* 自定义时间格式
* @param jsonText
public static String toJSON(String dateFormat, String jsonText) {
mapping.put(Date.class, new SimpleDateFormatSerializer(dateFormat));
return JSON.toJSONString(jsonText, mapping);
自定义反序列化示例:
先自定义一个日期解析类:
public class MyDateFormatDeserializer extends DateFormatDeserializer {
private String myF
public MyDateFormatDeserializer(String myFormat) {
this.myFormat = myF
protected &Date& Date cast(DefaultJSONParser parser, Type clazz, Object fieldName, Object val) {
if (myFormat == null) {
if (val instanceof String) {
String strVal = (String)
if (strVal.length() == 0) {
return (Date) new SimpleDateFormat(myFormat).parse((String)val);
} catch (ParseException e) {
throw new JSONException("parse error");
throw new JSONException("parse error");
public class User {
@JSONField(name = "com-google-com")
public void setName(String name) {
this.name =
@JSONField(format = "yyyy-MM/dd HH:mm:ss")
* @param args
* @throws IOException
public static void main(String[] args) throws IOException, ParseException {
String json = "{\"name\":\"22323\", \"age\": 1234," +
" \"birthday\": \" 12:12:12\"}";
Test t = JSON.parseObject(json, Test.class, mapping,
JSON.DEFAULT_PARSER_FEATURE, new Feature[0]);
System.out.println(t.name);
System.out.println(t.height);
System.out.println(t.birthday);
System.out.println(
new SimpleDateFormat("yyyy-MM/dd HH:mm:ss").parse(" 12:12:12"));
总结:对于JSONField注解,好像只对序列号的格式有影响,反序列化不管这个,不知道为什么,只能自己写个解析类了,不过这样就更灵活了,可以在里面写很多处理逻辑,比如json字符串里面日期格式并不是标准格式的时候,就可以先转成标准格式再去解析了。
另外,fastjson的document官网一直打不开,不知道神马原因,难道被feng了麽:
博客新地址:
浏览 24632
浏览: 332496 次
来自: 广州
我们(https://yunba.io/)是基于MQTT协议实 ...
感谢楼主分享
马马虎虎,还行吧。。哈哈哈哈
马马虎虎 还行吧
总体上还行吧,勉勉强强

我要回帖

更多关于 qq飞车充值点券 的文章

 

随机推荐