閱讀目錄
?
?
?
?
介紹
FastJson是阿里巴巴的開源JSON解析庫,它可以解析JSON格式的字符串,支持將Java Bean序列化為JSON字符串,也可以從JSON字符串反序列化到JavaBean。
FastJson已經(jīng)被廣泛使用在各種場景,包括cache存儲(chǔ)、RPC通訊、MQ通訊、網(wǎng)絡(luò)協(xié)議通訊、Android客戶端、Ajax服務(wù)器處理程序等等。
FastJson的API十分簡潔。
String text = JSON.toJSONString(obj); //序列化 VO vo = JSON.parseObject("{...}", VO.class); //反序列化
Maven依賴
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.54</version> </dependency>
JSON
com.alibaba.fastjson.JSON 這個(gè)類是FastJson API的入口,主要的功能都通過這個(gè)類提供。
String轉(zhuǎn)JSON
對(duì)于字符串的處理,主要是看這個(gè)字符串(jsonStr)是JSON對(duì)象格式還是JSON數(shù)組格式,然后選擇對(duì)應(yīng)的方法處理就行。
JSON對(duì)象字符串轉(zhuǎn)為JSON對(duì)象
JSONObject jsonObj = JSON.parseObject(jsonStr);
JSON數(shù)組字符串轉(zhuǎn)為JSON數(shù)組
JSONArray jsonArr = JSON.parseArray(jsonStr);
String轉(zhuǎn)JavaBean
Model model = JSON.parseObject(jsonStr, Model.class);
Object轉(zhuǎn)String
包括JSONObject、JSONArray、JavaBean、數(shù)組、List、Set、Map都可以通過這種方式轉(zhuǎn)String
String jsonStr = JSON.toJSONString(object);
JSONField
這是一個(gè)注解,用于配置在JavaBean,可以配置在getter/setter方法或者字段上,也可以直接配置在屬性上。
注意:若屬性是私有的,必須有set*方法。否則無法反序列化。
部分屬性
@JSONField(ordinal=1)//配置序列化的字段順序(1.1.42版本之后才支持) @JSONField(serialize=false) //是否參與序列化:該字段不輸出 但是如果加了final,這個(gè)字段就無法被過濾 @JSONField(derialize=false) //是否參與反序列化:該字段不輸出 但是如果加了final,這個(gè)字段就無法被過濾 @JSONField(format="yyyy-MM-dd HH:mm:ss") //日期按照指定格式序列化 @JSONField(name="別名");//使用字段別名 @JSONField(serialzeFeatures={SerialzeFeatures屬性});//序列化規(guī)則 @JSONField(parseFeatures={Features屬性});//反序列化規(guī)則
SerializerFeature屬性
public enum SerializerFeature { /** * 輸出key時(shí)是否使用雙引號(hào),默認(rèn)為true */ QuoteFieldNames, /** * 使用單引號(hào)而不是雙引號(hào),默認(rèn)為false */ UseSingleQuotes, /** * 是否輸出值為null的字段,默認(rèn)為false */ WriteMapNullValue, /** * 用枚舉toString()值輸出 */ WriteEnumUsingToString, /** * 用枚舉name()輸出 */ WriteEnumUsingName, /** * Date使用ISO8601格式輸出,默認(rèn)為false */ UseISO8601DateFormat, /** * @since 1.1 * List字段如果為null,輸出為[],而非null */ WriteNullListAsEmpty, /** * @since 1.1 * 字符類型字段如果為null,輸出為"",而非null */ WriteNullStringAsEmpty, /** * @since 1.1 * 數(shù)值字段如果為null,輸出為0,而非null */ WriteNullNumberAsZero, /** * @since 1.1 * Boolean字段如果為null,輸出為false,而非null */ WriteNullBooleanAsFalse, /** * @since 1.1 * 如果是true,類中的Get方法對(duì)應(yīng)的Field是transient,序列化時(shí)將會(huì)被忽略。默認(rèn)為true */ SkipTransientField, /** * @since 1.1 * 按字段名稱排序后輸出。默認(rèn)為false */ SortField, /** * @since 1.1.1 * 把 做轉(zhuǎn)義輸出,默認(rèn)為false(不推薦,已刪除) */ @Deprecated WriteTabAsSpecial, /** * @since 1.1.2 * 結(jié)果是否格式化,默認(rèn)為false */ PrettyFormat, /** * @since 1.1.2 * 序列化時(shí)寫入類型信息,默認(rèn)為false。反序列化時(shí)需用到 */ WriteClassName, /** * @since 1.1.6 * 消除對(duì)同一對(duì)象循環(huán)引用的問題,默認(rèn)為false */ DisableCircularReferenceDetect, /** * @since 1.1.9 * 對(duì)斜杠"/"進(jìn)行轉(zhuǎn)義 */ WriteSlashAsSpecial, /** * @since 1.1.10 * 將中文都會(huì)序列化為uXXXX格式,字節(jié)數(shù)會(huì)多一些,但是能兼容IE 6,默認(rèn)為false */ BrowserCompatible, /** * @since 1.1.14 * 全局修改日期格式,默認(rèn)為false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat); */ WriteDateUseDateFormat, /** * @since 1.1.15 */ NotWriteRootClassName, /** * @since 1.1.19 * 一個(gè)對(duì)象的字符串屬性中如果有特殊字符如雙引號(hào),將會(huì)在轉(zhuǎn)成json時(shí)帶有反斜杠轉(zhuǎn)移符。如果不需要轉(zhuǎn)義,可以使用這個(gè)屬性。默認(rèn)為false */ DisableCheckSpecialChar, /** * @since 1.1.35 * 將對(duì)象轉(zhuǎn)為array輸出 */ BeanToArray, /** * @since 1.1.37 */ WriteNonStringKeyAsString, /** * @since 1.1.42 */ NotWriteDefaultValue, /** * @since 1.2.6 */ BrowserSecure, /** * @since 1.2.7 */ IgnoreNonFieldGetter, /** * @since 1.2.9 */ WriteNonStringValueAsString, /** * @since 1.2.11 */ IgnoreErrorGetter; }
?Feature屬性
public enum Feature { /** * 這個(gè)特性,決定了解析器是否將自動(dòng)關(guān)閉那些不屬于parser自己的輸入源。 * 如果禁止,則調(diào)用應(yīng)用不得不分別去關(guān)閉那些被用來創(chuàng)建parser的基礎(chǔ)輸入流InputStream和reader; * 如果允許,parser只要自己需要獲取closed方法(當(dāng)遇到輸入流結(jié)束,或者parser自己調(diào)用 JsonParder#close方法),就會(huì)處理流關(guān)閉。 * 注意:這個(gè)屬性默認(rèn)是true,即允許自動(dòng)關(guān)閉流 */ AutoCloseSource, /** * 該特性決定parser將是否允許解析使用Java/C++ 樣式的注釋(包括'/'+'*' 和'//' 變量)。 * 由于JSON標(biāo)準(zhǔn)說明書上面沒有提到注釋是否是合法的組成,所以這是一個(gè)非標(biāo)準(zhǔn)的特性;盡管如此,這個(gè)特性還是被廣泛地使用。 * 注意:該屬性默認(rèn)是false,因此必須顯式允許,即通過JsonParser.Feature.ALLOW_COMMENTS 配置為true。 */ AllowComment, /** * 這個(gè)特性決定parser是否將允許使用非雙引號(hào)屬性名字, (這種形式在Javascript中被允許,但是JSON標(biāo)準(zhǔn)說明書中沒有)。 * 注意:由于JSON標(biāo)準(zhǔn)上需要為屬性名稱使用雙引號(hào),所以這也是一個(gè)非標(biāo)準(zhǔn)特性,默認(rèn)是false的。 * 同樣,需要設(shè)置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES為true,打開該特性。 */ AllowUnQuotedFieldNames, /** * 該特性決定parser是否允許單引號(hào)來包住屬性名稱和字符串值。 * 注意:默認(rèn)下,該屬性也是關(guān)閉的。需要設(shè)置JsonParser.Feature.ALLOW_SINGLE_QUOTES為true */ AllowSingleQuotes, /** * 該特性決定JSON對(duì)象屬性名稱是否可以被String#intern 規(guī)范化表示。如果允許,則JSON所有的屬性名將會(huì) intern() ; * 如果不設(shè)置,則不會(huì)規(guī)范化,默認(rèn)下,該屬性是開放的。此外,必須設(shè)置CANONICALIZE_FIELD_NAMES為true * 關(guān)于intern方法作用:當(dāng)調(diào)用 intern 方法時(shí),如果池已經(jīng)包含一個(gè)等于此 String 對(duì)象的字符串 (該對(duì)象由 equals(Object) 方法確定),則返回池中的字符串。 * 否則,將此 String 對(duì)象添加到池中, 并且返回此 String 對(duì)象的引用。 */ InternFieldNames, /** * 這個(gè)設(shè)置為true則遇到字符串符合ISO8601格式的日期時(shí),會(huì)直接轉(zhuǎn)換成日期類。 */ AllowISO8601DateFormat, /** * 允許多重逗號(hào),如果設(shè)為true,則遇到多個(gè)逗號(hào)會(huì)直接跳過。 * {"a":1,,,"b":2} */ AllowArbitraryCommas, /** * 這個(gè)設(shè)置為true則用BigDecimal類來裝載數(shù)字,否則用的是double; */ UseBigDecimal, /** * @since 1.1.2 * 忽略不匹配 */ IgnoreNotMatch, /** * @since 1.1.3 * 如果你用fastjson序列化的文本,輸出的結(jié)果是按照fieldName排序輸出的,parser時(shí)也能利用這個(gè)順序進(jìn)行優(yōu)化讀取。這種情況下,parser能夠獲得非常好的性能 */ SortFeidFastMatch, /** * @since 1.1.3 * 禁用ASM */ DisableASM, /** * @since 1.1.7 * 禁用循環(huán)引用檢測 */ DisableCircularReferenceDetect, /** * @since 1.1.10 * 對(duì)于沒有值的字符串屬性設(shè)置為空串 */ InitStringFieldAsEmpty, /** * @since 1.1.35 * 支持?jǐn)?shù)組to對(duì)象 */ SupportArrayToBean, /** * @since 1.2.3 * 屬性保持原來的順序 */ OrderedField, /** * @since 1.2.5 * 禁用特殊字符檢查 */ DisableSpecialKeyDetect, /** * @since 1.2.9 * 使用對(duì)象數(shù)組 */ UseObjectArray; }
測試代碼
目標(biāo)JavaBean代碼:
class User { //指定序列化字段順序,字段名稱 @JSONField(ordinal=4,name="ID") private Integer id; //指定序列化字段順序,不參加序列化 @JSONField(ordinal=3,serialize=false) private String name; //指定序列化字段順序,不參加反序列化 @JSONField(ordinal=2,deserialize=false) private Integer age; //指定序列化字段順序,日期格式 @JSONField(ordinal=1,format="yyyy-MM-dd") private Date creattime; //指定序列化規(guī)則,字段為null的時(shí)候依然參加序列化 @JSONField(serialzeFeatures=SerializerFeature.WriteMapNullValue) private String phone; public Integer getId() {return id;} public Date getCreattime() {return creattime;} public void setId(Integer id) {this.id = id;} public void setCreattime(Date creattime) {this.creattime = creattime;} public String getName() {return name;} public void setName(String name) {this.name = name;} public Integer getAge() {return age;} public void setAge(Integer age) {this.age = age;} public String getPhone() {return phone;} public void setPhone(String phone) {this.phone = phone;} @Override public String toString() { return "id="+id+"; name="+name+"; age="+age+"; createtime="+creattime; } };
測試代碼:
User user = new User(); user.setId(123456); user.setName("wangbo"); user.setAge(28); user.setCreattime(new Date()); String userStr = JSON.toJSONString(user); System.out.println(userStr); User user2 = JSON.parseObject(userStr, User.class); System.out.println(user2);
執(zhí)行結(jié)果:
userStr
{"phone":null,"creattime":"2018-12-04","age":28,"ID":123456}
user2
id=123456; name=null; age=null; createtime=Tue Dec 04 00:00:00 CST 2018
可以看出:
第一步序列化的結(jié)果:按照指定字段順序序列化的,id字段序列化為ID,name沒有參加序列化,createtime按照指定格式序列化,phone為null,但是參與了序列化。
(FastJson默認(rèn)的序列化規(guī)則是字段的值為null的時(shí)候,不參與序列化,serialzeFeatures=SerializerFeature.WriteMapNullValue可以在value的值為null的時(shí)候,依然會(huì)把它的值序列化出來。)
第二部反序列化結(jié)果:age沒有參與反序列化。
JSONPath
FastJson 1.2.0之后的版本支持JSONPath。這是一個(gè)很強(qiáng)大的功能,可以在java框架中當(dāng)作對(duì)象查詢語言(OQL)來使用。
API
public class JSONPath { //求值,靜態(tài)方法 public static Object eval(Object rootObject, String path); //計(jì)算size,Map非空元素個(gè)數(shù),對(duì)象非空元素個(gè)數(shù),Collection的Size,數(shù)組的長度。其他無法求值返回-1 public static int size(Object rootObject, String path); //是否包含,path中是否存在對(duì)象 public static boolean contains(Object rootObject, String path); //是否包含,path中是否存在指定值,如果是集合或者數(shù)組,在集合中查找value是否存在 public static boolean containsValue(Object rootObject, String path, Object value); //在數(shù)組或者集合中添加元素 public static void arrayAdd(Object rootObject, String path, Object... values); //修改制定路徑的值,如果修改成功,返回true,否則返回false public static boolean set(Object rootObject, String path, Object value); }
語法
JSONPATH | 描述 |
$ | 根對(duì)象,例如$.name |
[num] | 數(shù)組訪問,其中num是數(shù)字,可以是負(fù)數(shù)。例如$[0].leader.departments[-1].name |
[num0,num1,num2...] | 數(shù)組多個(gè)元素訪問,其中num是數(shù)字,可以是負(fù)數(shù),返回?cái)?shù)組中的多個(gè)元素。例如$[0,3,-2,5] |
[start:end] | 數(shù)組范圍訪問,其中start和end是開始小表和結(jié)束下標(biāo),可以是負(fù)數(shù),返回?cái)?shù)組中的多個(gè)元素。例如$[0:5] |
[start:end :step] | 數(shù)組范圍訪問,其中start和end是開始小表和結(jié)束下標(biāo),可以是負(fù)數(shù);step是步長,返回?cái)?shù)組中的多個(gè)元素。例如$[0:5:2] |
[?(key)] | 對(duì)象屬性非空過濾,例如$.departs[?(name)] |
[key > 123] | 數(shù)值類型對(duì)象屬性比較過濾,例如$.departs[id >= 123],比較操作符支持=,!=,>,>=,<,<= |
[key = '123'] | 字符串類型對(duì)象屬性比較過濾,例如$.departs[name = '123'],比較操作符支持=,!=,>,>=,<,<= |
[key like 'aa%'] | 字符串類型like過濾, 例如$.departs[name like 'sz*'],通配符只支持%? 支持not like |
[key rlike 'regexpr'] | 字符串類型正則匹配過濾, 例如departs[name like 'aa(.)*'], 正則語法為jdk的正則語法,支持not rlike |
[key in ('v0', 'v1')] | IN過濾, 支持字符串和數(shù)值類型? 例如:? $.departs[name in ('wenshao','Yako')]? $.departs[id not in (101,102)] |
[key between 234 and 456] | BETWEEN過濾, 支持?jǐn)?shù)值類型,支持not between? 例如:? $.departs[id between 101 and 201] $.departs[id not between 101 and 201] |
length() 或者 size() | 數(shù)組長度。例如$.values.size()? 支持類型java.util.Map和java.util.Collection和數(shù)組 |
. | 屬性訪問,例如$.name |
.. | deepScan屬性訪問,例如$..name |
* | 對(duì)象的所有屬性,例如$.leader.* |
['key'] | 屬性訪問。例如$['name'] |
['key0','key1'] | 多個(gè)屬性訪問。例如$['id','name'] |
?注意:以下兩種寫法的語義是相同的:
$.store.book[0].title
$['store']['book'][0]['title']
語法示例
JSONPath | 語義 |
$ | 根對(duì)象 |
$[-1] | 最后元素 |
$[:-2] | 第1個(gè)至倒數(shù)第2個(gè) |
$[1:] | 第2個(gè)之后所有元素 |
$[1,2,3] | 集合中1,2,3個(gè)元素 |
代碼示例
package com.wangbo.fastjson; import java.util.ArrayList; import java.util.Collection; import java.util.List; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONPath; public class Test { public static void main(String[] args) { String jsonStr = "{ " + " "store": { " + " "bicycle": { " + " "color": "red", " + " "price": 19.95 " + " }, " + " "book": [ " + " { " + " "author": "劉慈欣", " + " "price": 8.95, " + " "category": "科幻", " + " "title": "三體" " + " }, " + " { " + " "author": "itguang", " + " "price": 12.99, " + " "category": "編程語言", " + " "title": "go語言實(shí)戰(zhàn)" " + " } " + " ] " + " } " + "}"; JSONObject jsonObject = JSON.parseObject(jsonStr); System.out.println(jsonObject.toString()); //得到所有的書 List<Book> books = (List<Book>) JSONPath.eval(jsonObject, "$.store.book"); System.out.println("books=" + books); //得到所有的書名 List<String> titles = (List<String>) JSONPath.eval(jsonObject, "$.store.book.title"); System.out.println("titles=" + titles); //第一本書title String title = (String) JSONPath.read(jsonStr, "$.store.book[0].title"); System.out.println("title=" + title); //price大于10元的book List<Book> list = (List<Book>) JSONPath.read(jsonStr, "$.store.book[price > 10]"); System.out.println("price大于10元的book="+ list); //price大于10元的title List<String> list2 =(List<String>) JSONPath.read(jsonStr, "$.store.book[price > 10].title"); System.out.println("price大于10元的title=" + list2); //category(類別)為科幻的book List<Book> list3 = (List<Book>) JSONPath.read(jsonStr,"$.store.book[category = '科幻']"); System.out.println("category(類別)為科幻的book=" + list3); //bicycle的所有屬性值 Collection<String> values = (Collection<String>) JSONPath.eval(jsonObject, "$.store.bicycle.*"); System.out.println("bicycle的所有屬性值={}" + values); //bicycle的color和price屬性值 List<String> read =(List<String>) JSONPath.read(jsonStr, "$.store.bicycle['color','price']"); System.out.println("bicycle的color和price屬性值=" + read); } }
運(yùn)行結(jié)果
{"store":{"bicycle":{"color":"red","price":19.95},"book":[{"author":"劉慈欣","price":8.95,"category":"科幻","title":"三體"},{"author":"itguang","price":12.99,"category":"編程語言","title":"go語言實(shí)戰(zhàn)"}]}} books=[{"author":"劉慈欣","price":8.95,"category":"科幻","title":"三體"},{"author":"itguang","price":12.99,"category":"編程語言","title":"go語言實(shí)戰(zhàn)"}] titles=["三體","go語言實(shí)戰(zhàn)"] title=三體 price大于10元的book=[{"author":"itguang","price":12.99,"category":"編程語言","title":"go語言實(shí)戰(zhàn)"}] price大于10元的title=["go語言實(shí)戰(zhàn)"] category(類別)為科幻的book=[{"author":"劉慈欣","price":8.95,"category":"科幻","title":"三體"}] bicycle的所有屬性值={}[red, 19.95] bicycle的color和price屬性值=[red, 19.95]
本文摘自 :https://www.cnblogs.com/