> 文章列表 > 2.java程序员必知必会类库之json解析库

2.java程序员必知必会类库之json解析库

2.java程序员必知必会类库之json解析库

前言

百度百科解释

JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

在当今世界的web服务的数据交互中,JSON已经取代了XML,成为从客户端到服务器传送信息的首选协议。有一个好消息和一个坏消息。坏消息是JDK没有提供JSON库。好消息是有许多优秀的第三方库可以用来解析和创建JSON消息,如 fastjson和 Gson

fastjson

1.介绍

Git地址: https://github.com/alibaba/fastjson
Wiki:https://github.com/alibaba/fastjson/wiki
FAQ:https://github.com/alibaba/fastjson/wiki/常见问题

2. 使用

2.1. pom依赖引入

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

2.2 api使用

2.2.1 序列化对象转字符串
public class User {private String username;private Date birthday;private int sex;//省略getset tostring方法
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");User user2=new User();
user2.setUsername("wangpeng");
user2.setSex(0);
user2.setBirthday(new Date());List<User> userList=new ArrayList<User>();
userList.add(user);
userList.add(user2);
System.out.println(JSON.toJSONString(userList));
//[{"birthday":1681351631631,"sex":1,"username":"liming"},{"birthday":1681351631631,"sex":0,"username":"wangpeng"}]String str = JSONObject.toJSONString(user);
System.out.println(str);
//{"birthday":1681350602343,"sex":1,"username":"liming"}

这里jsonobject 和 JSONArray 实际继承的都是抽象父类JSON,两个类的很多方法实际都用的是JSON的方法,比如toJSONString

2.2.2 反序列化字符串转对象
String str="{\\"birthday\\":1681350739299,\\"sex\\":1,\\"username\\":\\"liming\\"}";
User user = JSONObject.parseObject(str, User.class);
System.out.println(user.toString());
//User{username='liming', birthday=Thu Apr 13 09:52:19 CST 2023, sex=1}String str2="[{\\"birthday\\":1681351631631,\\"sex\\":1,\\"username\\":\\"liming\\"},{\\"birthday\\":1681351631631,\\"sex\\":0,\\"username\\":\\"wangpeng\\"}]";
List<User> users = JSONArray.parseArray(str2, User.class);
System.out.println(users);
//[User{username='liming', birthday=Thu Apr 13 10:07:11 CST 2023, sex=1}, User{username='wangpeng', birthday=Thu Apr 13 10:07:11 CST 2023, sex=0}]

3.注意事项

3.1 版本问题

之前fastjson出现漏洞,为此,出于安全考虑,需要升级公司fastjson版本到1.2.83 以上,关于漏洞更多信息,可网上找相关内容深入了解

3.2 循环引用的问题

当进行toJSONString的时候,默认如果重用对象的话,会使用引用的方式进行引用对象。,详见下面代码示例

A a = new A();
B b = new B();
a.setB(b);
ArrayList<Object> objects = new ArrayList<Object>();
objects.add(a);
//这里和a重用b对象
objects.add(b);
String string = JSON.toJSONString(objects);
//可以看到序列化出来的数据带引用
System.out.println(string); //[{"b":{}},{"$ref":"$[0].b"}]
JSONArray array = JSON.parseArray(string);
//反序列化也可以看到实际引用对象地址是一样的
boolean isTheSameObject = array.getJSONObject(0).getJSONObject("b") == array.getJSONObject(1);
System.out.println(isTheSameObject);//true
//去除循环依赖检测
String deleteRefrenceStr = JSON.toJSONString(objects, SerializerFeature.DisableCircularReferenceDetect);
System.out.println(deleteRefrenceStr); //[{"b":{}},{}]
// 去除循环依赖后反序列化,可以看到生成的对象与原来的没有关系
JSONArray array2=JSON.parseArray(deleteRefrenceStr);
System.out.println(array2.getJSONObject(0).getJSONObject("b") == array2.getJSONObject(1));
//false

3.3 常见注解使用

3.3.1 JSONField注解

该注解主要用于在序列化和反序列化的时候,对我们要处理的对象做一些自己想要的定制化配置,而不是用通用的处理,注解属性如下:

package com.alibaba.fastjson.annotation;
public @interface JSONField {// 配置序列化和反序列化的顺序,1.1.42版本之后才支持int ordinal() default 0;// 指定字段的名称String name() default "";// 指定字段的格式,对日期格式有用String format() default "";// 是否序列化boolean serialize() default true;// 是否反序列化boolean deserialize() default true;
}

下面通过几个简单的例子展示如何使用该注解
注意:1、若属性是私有的,必须有set*方法。否则无法反序列化。

 public class A {@JSONField(name="ID")private int id;@JSONField(name="ID")public int getId() {return id;}@JSONField(name="ID")public void setId(int value) {this.id = id;}// 配置date序列化和反序列使用yyyyMMdd日期格式@JSONField(format="yyyyMMdd")public Date date;// 使用serialize/deserialize指定字段不序列化@JSONField(serialize=false)public Date birthday;//缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本@JSONField(ordinal = 3)private int f0;@JSONField(ordinal = 2)private int f1;@JSONField(ordinal = 1)private int f2;}
3.3.1.1 使用serializeUsing制定属性的序列化类

在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,

public static class Model {@JSONField(serializeUsing = ModelValueSerializer.class)public int value;
}public static class ModelValueSerializer implements ObjectSerializer {@Overridepublic void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,int features) throws IOException {Integer value = (Integer) object;String text = value + "元";serializer.write(text);}
}Model model = new Model();
model.value = 100;
String json = JSON.toJSONString(model);
Assert.assertEquals("{\\"value\\":\\"100元\\"}", json);
3.3.2 JSONType注解

在1.2.14版本之后,fastjson支持通过JSONType配置定制序列化的ObjectSerializer。使用如下

@JSONType(serializer=ModelSerializer.class)
public static class Model {public int id;
}public static class ModelSerializer implements ObjectSerializer {@Overridepublic void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,int features) throws IOException {Model model = (Model) object;SerializeWriter out = serializer.getWriter();out.writeFieldValue('{', "ID", model.id);out.write('}');}
}
Model model = new Model();
model.id = 1001;
String text = JSON.toJSONString(model);
Assert.assertEquals("{\\"ID\\":1001}", text);

3.4 序列化特性使用

上面有提到序列化去除循环依赖的使用特性,fastjson 也提供了很多其他序列化方式,这些序列化方式可以一起组合使用。下面代码我是从fastjson 源码里拷贝过来的。
通过英文名基本就能猜到使用相应特性的结果,这里就不一一赘述。

public enum SerializerFeature {
QuoteFieldNames,
UseSingleQuotes,
WriteMapNullValue,
WriteEnumUsingToString,
WriteEnumUsingName,
UseISO8601DateFormat,
WriteNullListAsEmpty,
WriteNullStringAsEmpty,
WriteNullNumberAsZero,
WriteNullBooleanAsFalse,
SkipTransientField,
SortField,
/ @deprecated */
@Deprecated
WriteTabAsSpecial,
PrettyFormat,
WriteClassName,
DisableCircularReferenceDetect,
WriteSlashAsSpecial,
BrowserCompatible,
WriteDateUseDateFormat,
NotWriteRootClassName,
/ @deprecated */
DisableCheckSpecialChar,
BeanToArray,
WriteNonStringKeyAsString,
NotWriteDefaultValue,
BrowserSecure,
IgnoreNonFieldGetter,
WriteNonStringValueAsString,
IgnoreErrorGetter,
WriteBigDecimalAsPlain,
MapSortField;
}

3.5 自定义序列化与反序列化

3.5.1 自定义序列化

参考官网,不再赘述

3.5.2 自定义反序列化

参考官网,不再赘述

4.与spring结合

参考官网介绍

Gson

1.介绍

GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。GSON笔者使用不多,这里只做简单介绍

2. 使用

2.1 pom坐标

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version>
</dependency>

2.2 api使用

2.2.1 对象序列化与反序列化demo

User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
//序列化  基本类型有默认值,包装类不解析
String str = new Gson().toJson(user);
System.out.println(str);
//{"username":"liming","birthday":"Apr 13, 2023 3:37:26 PM","sex":1}
User user2=new User();
user2.setUsername("wangpeng");
user2.setBirthday(new Date());
System.out.println(new Gson().toJson(user2));
//{"username":"wangpeng","birthday":"Apr 13, 2023 3:39:13 PM","sex":0}//反序列化
User userDeseri = new Gson().fromJson(str, User.class);
System.out.println(userDeseri);
//User{username='liming', birthday=Thu Apr 13 15:40:48 CST 2023, sex=1}
2.2.2 集合序列化与反序列化demo
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");User user2=new User();
user2.setUsername("wangpeng");
user2.setBirthday(new Date());List<User> userList=new ArrayList<User>();
userList.add(user);
userList.add(user2);
//集合序列化
String toJsonStr = new Gson().toJson(userList);
System.out.println(toJsonStr);
//[{"username":"liming","birthday":"Apr 13, 2023 3:48:50 PM","sex":1},{"username":"wangpeng","birthday":"Apr 13, 2023 3:48:50 PM","sex":0}]
//集合反序列化
Type type = new TypeToken<ArrayList<User>>(){}.getType();
List<User> users = new Gson().fromJson(toJsonStr, type);
System.out.println(users);
//[User{username='liming', birthday=Thu Apr 13 15:48:50 CST 2023, sex=1}, User{username='wangpeng', birthday=Thu Apr 13 15:48:50 CST 2023, sex=0}]

3.注意事项

3.1 指定序列化和反序列化字段名称

通过该注解,可以在序列化和反序列化的时候调整属性名称

public class User {@SerializedName("testuser")private String username;private Date birthday;private int sex;
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
String str = new Gson().toJson(user);
//{"testuser":"liming","birthday":"Apr 13, 2023 4:03:08 PM","sex":1}

3.2 忽略解析某个值

使用transient关键字修饰的属性,不参与序列化

public class User {private String username;private Date birthday;private transient int sex;
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
String str = new Gson().toJson(user);
//{"username":"liming","birthday":"Apr 13, 2023 3:56:22 PM"}

参考文献:
阿里巴巴fastjson github