Java解析JSON的利器有哪些

1. JSON 是什么

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,机器解析和生成起来更是轻而易举。JSON 采用了完全独立于编程语言的文本格式,但它的格式非常符合 C 语言家族的习惯(比如 C、C++、C#、Java、JavaScript、Python 等)。 这种特质使得 JSON 成为了最理想的数据交换格式。

JSON 建构于两种常见的数据结构:

“键/值”对。 数组。

这使得 JSON 在同样基于这些结构的编程语言之间的交换成为可能。在 Java 中,解析 JSON 的第三方类库有很多,比如说下面这些。
Screen Shot 2020-01-18 at 6.45.19 PM.png

很多,对不对?但日常开发中,最常用的只有四个:Gson、Jackson、org.json 和阿里巴巴的 fastjson。下面我们来简单地对比下。

2. Gson

Gson 是谷歌提供的一个开源库,可以将 Java 对象序列化为 JSON 字符串,同样可以将 JSON 字符串反序列化(解析)为匹配的 Java 对象。

使用 Gson 之前,需要先在项目中引入 Gson 的依赖。

<dependency>
    <groupId>com.google.code.gson</groupId>    
   <artifactId>gson</artifactId>
    <version>2.8.6</version>
    <scope>compile</scope>
</dependency>

1)简单示例

Gson gson = new Gson();
gson.toJson(18);            // ==> 18
gson.toJson("极客教程");       // ==> "极客教程"

上面这段代码通过 new 关键字创建了一个 Gson 对象,然后调用其 toJson() 方法将整形和字符串转成了 JSON 字符串。

同样,可以调用 fromJson() 方法将简单的 JSON 字符串解析为整形和字符串。

int one = gson.fromJson("18", int.class);
Integer one1 = gson.fromJson("18", Integer.class);
String str = gson.fromJson("\"极客教程\"", String.class);

2)复杂点的示例

Cmower 类有两个字段:整形 age 和 字符串 name。

class Cmower {
    private int age = 18;
    private String name = "极客教程";
}

将其转成 JSON 字符串。

Gson gson = new Gson();
String json = gson.toJson(new Cmower());
System.out.println(json);

输出结果为:

{"age":18,"name":"极客教程"}

可以再通过 fromJson() 方法将字符串 json 解析为 Java 对象。

gson.fromJson(json, Cmower.class);

3)数组示例

Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"极", "客", "教程"};
// 转成 JSON 字符串
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  // ==> ["极", "客", "教程"]
// 解析为数组
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
String[] strings2 = gson.fromJson("[\"极\", \"客\", \"教程\"]", String[].class);

数组的处理仍然非常简单,调用的方法也仍然是 toJson() 和 fromJson() 方法。

4)集合示例

Gson gson = new Gson();
List<String> list = new ArrayList<>(Arrays.asList("极", "客", "教程"));
String json = gson.toJson(list); // ==> ["极","客","教程"]

把集合转成 JSON 字符串并没有什么特别之处,不过,把 JSON 字符串解析为集合就和之前的方法有些不同了。

Type collectionType = new TypeToken<ArrayList<String>>(){}.getType();
List<String> list2 = gson.fromJson(json, collectionType);

我们需要借助 com.google.gson.reflect.TypeTokenjava.lang.reflect.Type 来获取集合的类型,再将其作为参数传递给formJson()方法,才能将 JSON 字符串解析为集合。

Gson 虽然可以将任意的 Java 对象转成 JSON 字符串,但将字符串解析为指定的集合类型时就需要花点心思了,因为涉及到了泛型——TypeToken 是解决这个问题的银弹。

3. Jackson

Jackson 是基于 Stream 构建的一款用来序列化和反序列化 JSON 的 Java 开源库,社区非常活跃,其版本的更新速度也比较快。

截止到目前,GitHub 上已经星标 5.2K 了; Spring MVC 的默认 JSON 解析器; 与 Gson 相比,Jackson 在解析大的 JSON 文件时速度更快。 与 fastjson 相比,Jackson 更稳定。

在使用 Jackson 之前,需要先添加 Jackson 的依赖。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.1</version>
</dependency>

Jackson 的核心模块由三部分组成。

jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 jackson-annotations,注解包,提供标准注解功能。 jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。

当添加 jackson-databind 之后, jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。

这里顺带推荐一个 IDEA 插件:JsonFormat,可以将 JSON 字符串生成一个 JavaBean。怎么使用呢?可以新建一个类,然后调出 Generate 菜单。
Screen Shot 2020-01-18 at 8.13.24 PM.png

选择 JsonFormat,输入 JSON 字符串。

{
  "age" : 18,
  "name" : "极客教程"
}

确认后生成 JavaBean,生成的内容如下所示。

public class Cmower {
    private Integer age;
    private String name;
    public Cmower() {
    } 
   public Cmower(Integer age, String name) {
        this.age = age;
        this.name = name;
    } 
   public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getName() {
        return name;
    } 
   public void setName(String name) { 
       this.name = name; 
   }}

那怎么使用 Jackson 呢?上文已经提到,ObjectMapper 是 Jackson 最常用的 API,我们来看一个简单的示例。

Cmower wanger = new Cmower(18,"极客教程");
System.out.println(wanger);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(wanger);
System.out.println(jsonString);
Cmower deserialize = mapper.readValue(jsonString,Cmower.class);
System.out.println(deserialize);

ObjectMapper 通过 writeValue() 的系列方法可以将 Java 对象序列化为 JSON,并将 JSON 存储成不同的格式。

String(writeValueAsString) Byte Array(writeValueAsBytes)

ObjectMapper 通过readValue()系列方法可以从不同的数据源(String、Bytes)将 JSON 反序列化(解析)为 Java 对象。

程序输出结果为:

com.cmower.java_demo.jackson.Cmower@214c265e
{
  "age" : 18,
  "name" : "极客教程"
}
com.cmower.java_demo.jackson.Cmower@612fc6eb

在调用writeValue()或者 readValue()方法之前,往往需要对 JSON 和 JavaBean 之间进行一些定制化配置。

1)在反序列化时忽略在 JSON 中存在但 JavaBean 不存在的字段

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

2)在序列化时忽略值为 null 的字段

apper.setSerializationInclusion(Include.NON_NULL);

有些时候,这些定制化的配置对 JSON 和 JavaBean 之间的转化起着重要的作用。如果需要更多配置信息,查看 DeserializationFeature、SerializationFeature 和 Include 类的 Javadoc 即可。

关于 Jackson,我们就说到这吧,以后有机会的时候再和大家细说。

4. org.json

org.json 是 JSON 官方提供的一个开源库,不过使用起来就略显繁琐了。

使用 org.json 之前,需要先在项目中引入 org.json 的依赖。

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20190722</version>
</dependency>

org.json.JSONObject 类可以通过 new 关键字将 JSON 字符串解析为 Java 对象,然后 get 的系列方法获取对应的键值,代码示例如下所示。

String str = "{ \"name\": \"极客教程\", \"age\": 18 }";
JSONObject obj = new JSONObject(str);
String name = obj.getString("name");
int age = obj.getInt("age");

调用 org.json.JSONObject 类的 getJSONArray() 方法可以返回一个表示数组的org.json.JSONArray 对象,再通过循环的方式可以获取数组中的元素,代码示例如下所示。

String str = "{ \"number\": [3, 4, 5, 6] }";
JSONObject obj = new JSONObject(str);
JSONArray arr = obj.getJSONArray("number");
for (int i = 0; i < arr.length(); i++) {
    System.out.println(arr.getInt(i));
}

如果想获取 JSON 字符串,可以使用 put() 方法将键值对放入 org.json.JSONObject 对象中,再调用 toString() 方法即可,代码示例如下所示。

JSONObject obj = new JSONObject();
obj.put("name","极客教程");
obj.put("age",18);
System.out.println(obj.toString()); // {"name":"极客教程","age":18}

相比较于 Gson 和 Jackson 来说,org.json 就要逊色多了,不仅不够灵活,API 也不够丰富。

5. fastjson

fastjson 是阿里巴巴开源的 JSON 解析库,它可以解析 JSON 格式的字符串,也支持将 Java Bean 序列化为 JSON 字符串。

fastjson 相对于其他 JSON 库的特点就是快,另外 API 使用起来也非常简单,更是在 2012 年被开源中国评选为最受欢迎的国产开源软件之一。

PS:尽管 fastjson 值得信赖,但也闹过不少腥风血雨,这里就不提了。

在使用 fastjson 之前,需要先添加 fastjson 的依赖。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.61</version>
</dependency>

那怎么使用 fastjson 呢?我们来创建一个 Java Bean,有三个字段:年龄 age,名字 name,列表 books。

class Cmower1 {
    private Integer age;
    private String name;
    private List<String> books = new ArrayList<>();
    public Cmower1(Integer age, String name) {
        this.age = age;
        this.name = name;
    }
   // getter/setter
    public void putBook(String bookname) {
        this.books.add(bookname); 
   }}

然后我们使用JSON.toJSONString() 将 Java 对象序列化为 JSON 字符串,代码示例如下:

Cmower1 cmower = new Cmower1(18,"极客教程");
cmower.putBook("《Web全栈开发进阶之路》");
String jsonString = JSON.toJSONString(cmower);
System.out.println(jsonString);

程序输出:

{"age":18,"books":["《Web全栈开发进阶之路》"],"name":"极客教程"}

那如何解析 JSON 字符串呢?使用JSON.parseObject() 方法,代码示例如下所示。

JSON.parseObject(jsonString, Cmower1.class)

6. 总结

就我个人而言,我是比较推崇 Gson 的,毕竟是谷歌出品的,品质值得信赖,关键是用起来也确实比较得劲。

Jackson 呢,在解析大的 JSON 文件时速度更快,也比 fastjson 稳定。

fastjson 呢,作为我们国产开源软件中的骄傲,嗯,值得尊敬。

令我意外的是,org.json 在 StackOverflow 上一个 160 万浏览量的提问中,牢牢地占据头名答案。更令我想不到的是,老板竟然也选择了 org.json,说它比较原生,JSON 官方的亲儿子。

相关文章:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容