JSON解析类库之Fastjson(1) --- Fastjson类库学习, 生成与解析json数据,json字符串与Java对象互转

版权声明:本文为博主(chunlynn)原创文章,转载请注明出处 https://blog.csdn.net/chenchunlin526/article/details/70209340
JSON解析类库之Fastjson(1) --- Fastjson基础知识、简单JavaBean与复杂Bean对象与JSON互转

-- Fastjson类库学习, 生成与解析json数据,json字符串与Java对象互转

在日志解析、前后端数据传输交互中,经常会遇到 String 与 map、json、xml 等格式相互转换与解析的场景,其中 json 基本成为了跨语言、跨前后端的事实上的标准数据交互格式。应该来说各个语言中解析 json 的库都一大片(具体 json 格式与三方库的介绍请见: http://www.json.org/json-zh.html ),比如 python 都集成在了内置库中,成为标准 API,今天我们要聊的是 java 中如何方便的使用 json 格式。

从上面的链接介绍中我们可以看到,java 的三方 json 库是最多的,可谓百花齐放百家争鸣的节奏。。。但是,某些库存在链式依赖的问题,使用的时候要注意,如果你没用 maven 管你你的依赖,用起来会很痛苦,比如 json-lib、smart-json 等。下面我要推荐的是阿里巴巴公司开源的一个 json 库:Fastjson,这个库在解析速度易用性上来说都很优秀。  

1、Fastjson简介:
Fastjson是一个Java语言编写的高性能功能完善的JSON库(JSON处理器,解析类库)。
1、遵循http://json.org标准,为其官方网站收录的参考实现之一。
2、功能强大,支持JDK的各种类型,包括基本类型、JavaBean、Collection、Map、Date、Enum、泛型等。
3、无依赖,不需要例外额外的jar,能够直接跑在JDK上。
4、开源,使用Apache License 2.0协议开源。
5、测试充分,fastjson有超过1500个testcase,每次构建都会跑一遍,丰富的测试场景保证了功能稳定。


Fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jackson。并且还超越了google的二进制协议protocol buf。Fastjson完全支持http://json.org的标准,也是官方网站收录的参考实现之一。支持各种JDK类型。包括基本类型、JavaBean、Collection、Map、Enum、泛型等。支持JDK 5、JDK 6、Android、阿里云手机等环境。

阿里巴巴FastJson是一个Json处理工具包,包括“序列化”和“反序列化”两部分,它具备如下特征:
速度最快,测试表明,fastjson具有极快的性能,超越任其他的Java Json parser。包括自称最快的Jackson
功能强大,完全支持Java Bean、集合、Map、日期、Enum,支持范型,支持自省;无依赖,能够直接运行在Java SE 5.0以上版本;支持Android;开源 (Apache 2.0)

如何获得Fastjson?
你可以通过如下地方下载fastjson:
maven中央仓库: http://central.maven.org/maven2/com/alibaba/fastjson/
Sourceforge.net : https://sourceforge.net/projects/fastjson/files/
在maven中如何配置fastjson依赖 :
fastjson最新版本都会发布到maven中央仓库,你可以直接依赖。

如果没有使用maven,可以直接下载:
csdn下载http://download.csdn.net/detail/chenchunlin526/9816420 【最新1.2.31版,包括jar包,和源码包】
http://repo1.maven.org/maven2/com/alibaba/fastjson/   【包含各个版本,下载快】
https://github.com/alibaba/fastjson   【源码发布地方】


版本建议:建议使用1.2.28及其以后的版本,之前的1.2.24之前的版本说是有个小漏洞,之后的版本已经修复了。

2. fastjson主要的API哪些?

fastjson入口类是com.alibaba.fastjson.JSON,主要的APIJSON.toJSONString,和parseObject

package com.alibaba.fastjson;
public abstract class JSON {
      public static final String toJSONString(Object object);
      public static final <T> T parseObject(String text, Class<T> clazz, Feature... features);
}

序列化:

基本序列化

序列化就是把JavaBean对象转化成JSON格式的文本。

String jsonString = JSON.toJSONString(obj);

反序列化:

VO vo = JSON.parseObject("...", VO.class);

泛型反序列化:

import com.alibaba.fastjson.TypeReference;

List<VO> list = JSON.parseObject("...", new TypeReference<List<VO>>() {});

fastjson的一些高级特性:
使用单引号:
标准的JSON是使用双引号的,javascript支持使用单引号格式的json文本,fastjson也支持这个特性,打开SerializerFeature.UseSingleQuotes这个特性就可以了了,例如:
Object o = ...;
String text = JSON.toJSONString(o, SerializerFeature.UseSingleQuotes);
fastjson序列化时可以选择的SerializerFeature有十几个,你可以按照自己的需要去选择使用。

日期格式化
fastjson直接支持日期类型数据的格式化,包括java.util.Date、java.sql.Date、java.sql.Timestamp、java.sql.Time。
默认情况下,fastjson将Date类型序列化为long这个使得序列化和反序列化的过程不会导致时区问题。如:
例如:
long  millis = 1324138987429L;
Date date = new  Date(millis);        
System.out.println(JSON.toJSONString(date));
输出的结果是:
1324138987429

fastjson还提供了基于格式化输出的SerializerFeature,例如:
JSON.toJSONString(date, SerializerFeature.WriteDateUseDateFormat);
输出的结果为:
"2011-12-18 00:23:07"
你可以指定输出日期的格式,比如修改为输出毫秒:
JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS");
输出的结果为:
"2011-12-18 00:23:07.429"

使用WriteClassName特性
fastjson支持序列化时写入类型信息,从而使得反序列化时不至于类型信息丢失。例如:
Color color = Color.RED;
String text = JSON.toJSONString(color, SerializerFeature.WriteClassName);
System.out.println(text);
输出结果:
{"@type":"java.awt.Color","r":255,"g":0,"b":0,"alpha":255}
由于序列化带了类型信息,使得反序列化时能够自动进行类型识别,例如:
String text = ...; // {"@type":"java.awt.Color","r":255,"g":0,"b":0,"alpha":255}
Color color = (Color) JSON.parse(text);

浏览器和设备兼容
fastjson默认的序列化内容,是对序列化结果紧凑做了优化配置,使得序列化之后长度更小,但是这种优化配置是对一些浏览器和设备不兼容的。比如说在iphone上兼容emoji(绘文字)。
JSON.toJSONString(o, SerializerFeature.BrowserCompatible);

循环引用
很多场景中,我们需要序列化的对象中存在循环引用,在许多的json库中,这会导致stackoverflow。在功能强大的fastjson中,你不需要担心这个问题。例如:
A a = new  A();
B b = new  B(a);
a.setB(b);
 
String text = JSON.toJSONString(a); // {"b":{"a":{"$ref":".."}}}
A a1 = JSON.parseObject(text, A.class);
Assert.assertTrue(a1 == a1.getB().getA());

引用是通过"$ref"来表示的

引用 描述
"$ref":".." 上一级
"$ref":"@" 当前对象,也就是自引用
"$ref":"$" 根对象
"$ref":"$.children.0" 基于路径的引用,相当于 root.getChildren().get(0)

使用@JSONField Annotation注解

在某些场景,你可能需要定制序列化输出,比如说,希望序列化之后采用"ID",而不是"id",你可以使用@JSONField这个Annotation。

public class User {

    @JSONField(name="ID")

    public int getId() { ... }

}

User user = ...;

JSON.toJSONString(user); // {"ID":234}


从json-lib中升级

如果你已经使用了json-lib,并且痛恨他蜗牛般的速度和罗嗦的API,建议你升级为fastjson,fastjson可以完全兼容json-lib的序列化格式。

import  com.alibaba.fastjson.JSON;

import  com.alibaba.fastjson.serializer.JSONLibDataFormatSerializer;

import  com.alibaba.fastjson.serializer.JSONSerializerMap;

import  com.alibaba.fastjson.serializer.SerializerFeature;

  

private static final SerializeConfig  config;

static  {

    config = new  SerializeConfig();

    config.put(java.util.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式

  

private  static  final  SerializerFeature[] features = {

        SerializerFeature.WriteMapNullValue// 输出空置字段

        SerializerFeature.WriteNullListAsEmpty// list字段如果为null,输出为[],而不是null

        SerializerFeature.WriteNullNumberAsZero// 数值字段如果为null,输出为0,而不是null

        SerializerFeature.WriteNullBooleanAsFalse// Boolean字段如果为null,输出为false,而不是null

        SerializerFeature.WriteNullStringAsEmpty // 字符类型字段如果为null,输出为"",而不是null

  };

  

// 序列化为和JSON-LIB兼容的字符串

public static String toCompatibleJSONString(Object object) {

    return  JSON.toJSONString(object, config, features);

}

通过上面代码中的toCompatibleJSONString方法,你就可以实现完全兼容json-lib了。


反序列化

反序列化就是把JSON格式的文本转化为Java Bean对象。


指定Class信息反序列化

通过指定类型信息,可以很方便的将"JSON文本"反序列化为"Java Bean"对象,例如:

String text = ...; // {"r":255,"g":0,"b":0,"alpha":255}

Color color = JSON.parseObject(text, Color.class);


类型集合的反序列化

这个接口类似于parseObject

String text = ...; // [{ ... }, { ... }]

List<User> users = JSON.parseArray(text, User.class);


泛型的反序列化

如果你需要返回一个带泛型的对象,例如List<User>、Map<String, User>,你可以使用TypeReference来传入类型信息。

String text = ...; // {"name":{"name":"ljw",age:18}}

Map<String, User> userMap = JSON.parseObject(text, new TypeReference<Map<String, User>>(){});


组合类型集合的反序列化

比如在网络协议中,经常会存在这样的组合:

[{/*header*/}, {/*body*/}]

fastjson对这种结构的反序列化有专门支持。

String text = ...; // [{/* header */}, {/* body */}]

Type[] types = new  Type[]{Header.class, Body.class};

List<Object> list = JSON.parseArray(text, types);

Header header = (Header) list.get(0);

Body body = (Body) list.get(1);


使用@JSONCreator来指定构造函数来创建对象

如果你的JavaBean没有缺省构造函数,可以使用@JSONCreator来指定构造函数

public static class Entity {

    private  final  int     id; //应该用Integer才符合规范

    private  final  String name;

 

    @JSONCreator

    public  Entity(@JSONField(name = "id") int  id, @JSONField(name = "name") String name){

        this.id = id;

        this.name = name;

    }

 

    public  int  getId() { return  id; }

    public  String getName() { return  name; }

}


把JSON文本反序列化为一个原型接口

public static interface Bean { //接口

    int  getId();

    void  setId(int  value);

    String getName();

    void  setName(String value);

}

 

String text = "{\"id\":123, \"name\":\"chris\"}";

Bean bean = JSON.parseObject(text, Bean.class);

 

// 按接口调用

Assert.assertEquals(123, bean.getId());

Assert.assertEquals("chris", bean.getName());

bean.setId(234);

Assert.assertEquals(234, bean.getId());


。。。未完,待续

展开阅读全文

没有更多推荐了,返回首页