JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在当今世界的web服务的数据交互中,JSON已经取代了XML,成为从客户端到服务器传送信息的首选协议。有一个好消息和一个坏消息。坏消息是JDK没有提供JSON库。好消息是有许多优秀的第三方库可以用来解析和创建JSON消息,如 fastjson和 Gson
Git地址: https://github.com/alibaba/fastjson
Wiki:https://github.com/alibaba/fastjson/wiki
FAQ:https://github.com/alibaba/fastjson/wiki/常见问题
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.83version>
dependency>
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
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}]
之前fastjson出现漏洞,为此,出于安全考虑,需要升级公司fastjson版本到1.2.83 以上,关于漏洞更多信息,可网上找相关内容深入了解
当进行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
该注解主要用于在序列化和反序列化的时候,对我们要处理的对象做一些自己想要的定制化配置,而不是用通用的处理,注解属性如下:
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;
}
在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,
public static class Model {
@JSONField(serializeUsing = ModelValueSerializer.class)
public int value;
}
public static class ModelValueSerializer implements ObjectSerializer {
@Override
public 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);
在1.2.14版本之后,fastjson支持通过JSONType配置定制序列化的ObjectSerializer。使用如下
@JSONType(serializer=ModelSerializer.class)
public static class Model {
public int id;
}
public static class ModelSerializer implements ObjectSerializer {
@Override
public 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);
上面有提到序列化去除循环依赖的使用特性,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;
}
参考官网,不再赘述
参考官网,不再赘述
参考官网介绍
GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。GSON笔者使用不多,这里只做简单介绍
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>2.8.5version>
dependency>
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}
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}]
通过该注解,可以在序列化和反序列化的时候调整属性名称
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}
使用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