JSON解析框架汇总

1、JSON简介

json(JavaScript Object Notation),JavaScript对象表示法。json作为数据格式的一种,有很多优势,下面例子可帮大家更好的理解json格式:

 Person p = new Person();
 p.setName("张三");
 p.setAge(23);
 p.setGender("男");
var p = {"name":"张三","age":23,"gender":"男"};

可以看到,json本质就是将java对象转换之后的字符串,对象内容通过k,v键值对的形式表示。

  • json现在多用于存储和交换文本信息的语法
  • 进行数据的传输
  • JSON 比 XML 更小、更快,更易解析

因此,在日常开发中json数据的解析就是必不可少的技能包。


2、JSON解析框架简介

  • Jsonlib:是以前 Java 常用的一个 Json 库,最后的版本是 2.4,分别提供了 JDK 1.3 和 1.5 的支持,最后更新时间是 2010年12月14日。由于解析json时会对当前解析位置到末尾进行subString的操作,所以在解析较长的字符串时大量的 CPU 和内存消耗。因此现已不推荐使用;
  • GSON:由Google提供的开源库(下面会详细介绍);
  • FastJSON:由Alibaba提供的开源库(下面会详细介绍);
  • Jackson:SpringMVC内置解析器(下面会详细介绍)。

1、GSON

maven

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

基本用法

1、创建实例

new Gson()
Gson gson = new Gson();
GsonBuilder.build()
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();

2、java对象->json

String json = gson.toJson(java对象);

//上面的json直接控制台输出没有格式,可以这样
Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();
String json = gson.toJson(java对象);

3、json->java对象

Employee empObject = gson.fromJson(jsonString, Employee.class);

4、JSON array --> Java array/list

User[] userArray = gson.fromJson(userJson, User[].class);  

5、JSON array-->List

String userJson = "[{'name': 'Alex','id': 1}, " + "{'name': 'Brian','id':2}, " + "{'name': 'Charles','id': 3}]";

Gson gson = new Gson();

java.lang.reflect.Type userListType = new TypeToken<ArrayList<User>>() {
}.getType();

ArrayList<User> userArray = gson.fromJson(userJson, userListType);

for (User user : userArray) {
    System.out.println(user);
}

6、JSON array-->成员变量

数组成员变量

String departmentJson = "{'id' : 1, "
        + "'name': 'HR',"
        + "'users' : ["
            + "{'name': 'Alex','id': 1}, "
            + "{'name': 'Brian','id':2}, "
            + "{'name': 'Charles','id': 3}]}";
 
Gson gson = new Gson(); 
 
Department department = gson.fromJson(departmentJson, Department.class);  
 
System.out.println(department);

list成员变量

String departmentJson = "{'id' : 1, "
    + "'name': 'HR',"
    + "'users' : ["
    + "{'name': 'Alex','id': 1}, "
    + "{'name': 'Brian','id':2}, "
    + "{'name': 'Charles','id': 3}]}";

Gson gson = new Gson(); 

Department2 department = gson.fromJson(departmentJson, Department2.class);  

System.out.println(department);

7、JSON <---->Set

Set-->JSON
Set<String> userSet = new HashSet<String>();
userSet.add("Alex");
userSet.add("Brian");
userSet.add("Charles");

Gson gson = new Gson(); 

String jsonString= gson.toJson(userSet);  

System.out.println(jsonString);
JSON-->Set
String jsonString = "['Alex','Brian','Charles','Alex']";

Gson gson = new Gson(); 

java.lang.reflect.Type setType = new TypeToken<HashSet<String>>(){}.getType();

Set<String> userSet = gson.fromJson(jsonString, setType);  

System.out.println(userSet);

8、null

实体类有为空的字段,转为json时会忽略,为此行为允许使用更紧凑的JSON输出格式。

怎么允许空值?
Gson gson = new GsonBuilder()
        .serializeNulls()
        .create();

9、JsonParser(\color{red}{主要用法})

创建JsonParser
JsonParser parser = new JsonParser();
转化JSON

JsonParser类提供3种方法来提供JSON作为源并将其解析为JsonElements树。

  • JsonElement parse(JsonReader json)–使用JsonReader读取JSON作为令牌流,并从JSON流中返回下一个值作为分析树。
  • JsonElement parse(java.io.Reader json)–使用指定的阅读器读取JSON并将JSON字符串解析为解析树。
  • JsonElement parse(java.lang.String json)–将指定的JSON字符串解析为解析树。

如果指定的文本不是有效的JSON,则这三个方法都将抛出JsonParseException和JsonSyntaxException。

JsonElement, JsonObject 和JsonArray

通过:

JsonElement jsonElement = new JsonParser().parse(json);

将json转为JsonElement后可通过以下方法判断具体类型:(返回值:boolean):

jsonElement.isJsonObject();         //是否为对象
jsonElement.isJsonArray();          //是否为数组
jsonElement.isJsonNull();           //是否为空
jsonElement.isJsonPrimitive();      //是否为java基本类型

然后可以解析为具体类型:

JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonArray jsonArray = jsonElement.getAsJsonArray();

然后对JsonObject通过get方法提取字段

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
 
public class Main 
{
    public static void main(String[] args) throws Exception 
    {
        String json = "{'id': 1001, "
                + "'firstName': 'Lokesh',"
                + "'lastName': 'Gupta',"
                + "'email': 'howtodoinjava@gmail.com'}";
 
        JsonElement jsonElement = new JsonParser().parse(json);
         
        JsonObject jsonObject = jsonElement.getAsJsonObject();
 
        System.out.println( jsonObject.get("id") );
        System.out.println( jsonObject.get("firstName") );
        System.out.println( jsonObject.get("lastName") );
        System.out.println( jsonObject.get("email") );
    }
}

此外还有getAsJsonObject,getAsInt等方法

JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(response);
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonObject data = jsonObject.getAsJsonObject("data");
jsonObject.get("status").getAsInt()

2、FastJSON

maven

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

序列化(java---json)

1.基本的序列化

String objJson = JSON.toJSONString(Object object);
Map<String, Object> map = new HashMap<String, Object>();
map.put("key1", "One");
map.put("key2", "Two");
String mapJson = JSON.toJSONString(map);

2.优化输出

//第二个参数布尔为true时,json为有格式的字符串
String objJson = JSON.toJSONString(Object object, boolean prettyFormat);

3.多特性

String objJson = JSON.toJSONString(Object object, SerializerFeature... features) 

传入一个对象和SerializerFeature类型的可变变量。SerializerFeature是一个枚举。

  • 日期格式化:
//缺省会转为long     1401370199040
String dateJson = JSON.toJSONString(new Date());
//SerializerFeature.WriteDateUseDateFormat 默认格式
//"2014-05-29 21:36:24"
String dateJson = JSON.toJSONString(new Date(), SerializerFeature.WriteDateUseDateFormat);
//指定日期格式
//"2014-05-29 21:47:00.154"
String dateJson = JSON.toJSONStringWithDateFormat(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
  • 使用单引号(正常是双引号)
String listJson = JSON.toJSONString(list, SerializerFeature.UseSingleQuotes);
  • 输出Null字段,缺省不输出null
String listJson = JSON.toJSONString(map, SerializerFeature.WriteMapNullValue);

//输出
//{"a":null,"b":1}

反序列化(json---java)

1.对象

User user1 = JSON.parseObject(userJson, User.class);

2.集合

List<Map> list1 = JSON.parseArray(listJson, Map.class);
List<User> list1 = JSON.parseArray(listJson, User.class);

3.JSONObject/JSONArray(\color{red}{主要用法})

JSONObject/JSONAArray 是 JSON 的子类

JSONObject对象

  • 获取基本类型
String str = jsonObject.getString("str");
Long long = jsonObject.getLong("long");
Date date = jsonObject.getDate("date");
byte[] byte = jsonObject.getBytes("byte");
......
  • 获取对象
User user = jsonObject.getObject(userJson, User.class);
Object o = jsonObject.get(object);//可以传任意类型
  • 获取JSONObject对象
JSONObject jsonObject = jsonObject.getJSONObject("jsonObject");
  • 获取JSONArray对象
JSONArray jsonArray = jsonObject.getJSONArray("jsonArray");
  • 骚操作
image-20210622165014494

JSONObject底层实现了Map,所以可以使用Map API对JSONObject对象操作,如:put,isEmpty,remove

JSONArray对象

  • 获取基本类型(返回第几位置处的数据)
Long long = jsonArray.getLong(1);
String str = jsonArray.getString(1);
Date date = jsonArray.getDate(1);
  • 获取对象
Object o = jsonArray.get(1);
User user = jsonArray.getObject(1, User.class);
  • 获取JSONObject对象
JSONObject jsonObject = jsonArray.getJSONObject(1);
  • 获取JSONArray对象
JSONArray jsonArray1 = jsonArray.getJSONArray(1);
  • 骚操作
image-20210622173805349.png

JSONArray底层实现了List接口,所以可以使用List API操作JSONArray对象,如:add,size,clear,contains

代码示例解析:

String user = "{\"id\":12,\"name\":\"wei\",\"teacher\":{\"name\":\"kasa\",\"age\":77},\"student\":[{\"id\":2,\"name\":\"lily\",\"age\":12},{\"id\":3,\"name\":\"mary\",\"age\":23}]}";
JSONObject jsonObject = JSON.parseObject(user);
Long id  = jsonObject.getLong("id");
String name = jsonObject.getString("name");
JSONObject jsonObjectTeacher = jsonObject.getJSONObject("teacher");
String teacherName = jsonObjectTeacher.getString("name");
JSONArray jsonArray = jsonObject.getJSONArray("student");
for (Object o : jsonArray){
    JSONObject j = (JSONObject) o;
    Long studentId  = j.getLong("id");
    String studentName = j.getString("name");
}

String userString = "{\"id\":2,\"name\":\"lily\",\"age\":12}";
//json字符串转javabean
User user = JSON.parseObject(userString, new TypeReference<User>(){});
//javabean转json字符串
String userJsonString = JSON.toJSONString(user);
//javabean转jsonObject
JSONObject jsonObject = (JSONObject) JSON.toJSON(user);

String userArrayString = "[{\"id\":2,\"name\":\"lily\",\"age\":12},{\"id\":3,\"name\":\"mary\",\"age\":23}]";
//jsonArray转javabean集合
ArrayList<User> userList = JSON.parseObject(userArrayString, new TypeReference<ArrayList<User>>(){});

//对象转map
Map<String,Object> map = JSON.parseObject(JSON.toJSONString(user), new TypeReference<Map<String,Object>>(){});

//map转对象
org.apache.commons.beanutils.BeanUtils.populate(obj, map);

3、JackSon

\color{red}{JackSon拓展性强,本人才疏学浅,以下只做简单使用介绍}

\color{red}{操作基本都是基于核心类ObjectMappe}

maven

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

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

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.2</version>
</dependency>

当SpringBoot项目中引入以下依赖时不用再引入jackson依赖(内置)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

序列化(java---json)

1、writeValueAsString(obj)

作用:将java对象转为字符串

User user = new User();
user.setId("111");
user.setName("zs");
ObjectMapper objectMapper = new ObjectMapper();
String userJson = objectMapper.writeValueAsString(user);
System.out.println(userJson);

2、writeValue(参数1,obj)

作用:将java对象转为为json并传入参数中

参数1:

  • File:将obj对象转换为JSON字符串,并保存到指定的文件中;
  • Writer:将obj对象转换为JSON字符串,并将json数据填充到字符输出流中;
  • OutputStream:将obj对象转换为JSON字符串,并将json数据填充到字节输出流中。

反序列化(json---java)

readValue(参数1,Class)

作用:将参数1中的json转为java对象

参数1:

  • String:将字符串转为参数2 class 的对象
  • File:将File对象里的json转为class对象
  • ......

参数2:

  • 普通java类
  • 集合(需要借助TypeReference<T> 实现)

示例:

ObjectMapper mapper = new ObjectMapper();

Map<String, Object> map = new HashMap<>();
map.put("age", 25);
map.put("name", "yitian");
map.put("interests", new String[]{"pc games", "music"});

String text = mapper.writeValueAsString(map);
System.out.println(text);

Map<String, Object> map2 = mapper.readValue(text, new TypeReference<Map<String, Object>>() {
});
System.out.println(map2);

JsonNode root = mapper.readTree(text);
String name = root.get("name").asText();
int age = root.get("age").asInt();

System.out.println("name:" + name + " age:" + age);

结果:

{"name":"yitian","interests":["pc games","music"],"age":25}
{name=yitian, interests=[pc games, music], age=25}
name:yitian age:25

Jackson配置

// 美化输出
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// 允许序列化空的POJO类
// (否则会抛出异常)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 把java.util.Date, Calendar输出为数字(时间戳)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// 在遇到未知属性的时候不抛出异常
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 强制JSON 空字符串("")转换为null对象值:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

// 在JSON中允许C/C++ 样式的注释(非标准,默认禁用)
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// 允许没有引号的字段名(非标准)
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 允许单引号(非标准)
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 强制转义非ASCII字符
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
// 将内容包裹为一个JSON属性,属性名由@JsonRootName注解指定
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

注解配置

  • 属性使用的注解
@JsonProperty("NickName")//序列化后的json字段为NickName
private String name;

@JsonIgnore //标注的字段不参与序列化

  • 实体类使用的注解
1、
    //实体类使用的注解,用于序列化的时候忽略指定的一系列属性,或者反序列化的时候忽略未知的属性(没有getter/setter的属性)。
@JsonIgnoreProperties
序列化的时候,@JsonIgnoreProperties({"prop1", "prop2"}),忽略列表中的属性。
反序列化的时候,@JsonIgnoreProperties(ignoreUnknown=true),忽略没有get/set的属性。
    
2、
//实体类使用的注解,表示该类被忽略。
@JsonIgnoreType    
    
  • 公用注解
1、
//实体类/属性使用的注解,用于忽略NULL的属性,空的属性或者NULL的类。
@JsonInclude
    
2、
//实体类/属性使用的注解,在序列化或者反序列化的时候,指定属性格式化日期/时间。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",
                timezone = "GMT+8")
    private Date birthday;

SpringBoot中使用

引入依赖后,直接在yml文件中就可以配置

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

推荐阅读更多精彩内容