『壹』 當 json 遇到 Map
了解一下日常開發中關於 Json 解析的一些非常規用法,以及使用 fastjson 的一些總結。
一般情況 Json 的使用都是非常簡單的。 我們會根據上游定義的 Json 數據格式,由下游定義相應的解析模型。比如像下面這個簡單的 Json 字元串。
一般會定義如下的數據類(以 Kotlin 為例)
具體使用也是非常簡單了,無論是藉助 fastjson 、gson 或者是原生的 JsonObject 都可以非常方便的完成數據的序列化和反序列操作,比如以 fastjson 為例。
無論原始的 Json 數據格式多麼的復雜,包含原始數據類型、List、數組還是他類型, 只要需要解析的屬性的 key 是確定的,那麼就可以定義出相應的數據模型來解析 。 因為在定義任何一個數據模型是時,對於其中的每一個欄位(或者叫做屬性、類成員),唯一需要確定的就是變數的類型和變數名的名稱,比如面對下面這個略顯復雜的 Json :
我們依舊可以定義出如下的數據模型
但有時候我們會遇到 Json 數據中,key 值無法確定的情況。也就是說,我們需要解析的欄位名是不確定的。或者說,Json 數據中欄位名和欄位值重合的情況。
比如上面這個 Json ,按照日期返回一個 List(至於 List 里具體是什麼,我們也無需關心)或者是其他任何數據,這里就比較有意思了。
既然返回的屬性名是無法確定的,那麼怎麼定義 Json 對應的數據類型中的變數名呢 ?
上面 ??? 這里應該怎麼定義呢? 畢竟總不能窮舉所有日期吧? 再說也窮舉不過來呀,時間是無限的呀。
這里就需要轉換一下思路了,我們從本質出發,這里整個 Json 其實是一個 Map 。既然是一個 Map ,那我們就把他當做一個 Map 去解析好了。
因此,fastjson 在解析的時候不知道具體該怎麼辦了,只知道這是個把原始 Json 字元串解析為一個 Map 。剩下的就該靠我們自己了. fastjson 不知道具體類型,我們自己是知道的呀。因此,就需要遍歷 map 自己去處理了。
到這里,我們就可以獲取到原始 Json 字元串中的數據了。可以看到,對於上游返回的 Map 這種類型的數據,由於其本身靈活的特性,我們需要按具體的類型做具體拆解,沒有通用的方法。
作為常用的 Json 序列化框架 ,這里總結一下使用 fastjson 遇到一些坑和收獲。
日常開發中上游給我們的 Json 數據往往是很豐富的,並且由於 json 的特性,在一大段字元串中要找到我們關系的欄位是有點困難的,因此我們往往把 Json 字元串貼到各類 Json解析助手之類的網站或工具里,進行格式化。其實,不用那麼麻煩,fastjson 自身提供了可以格式化列印 Json 的方法。
這里格式化列印一下剛才的 map printBeautyJson(map)
從截圖可以看到,已經實現了 Json 的格式化輸出。SerializerFeature 還有很多其他很多實用的功能,可以按需要進行配置。
JSONField 是一個定義在 fastjson 內的註解,其中最常用的兩個值是 serialize 和 deserialize ,都是 boolean 類型,用戶決定對特定欄位進行序列化和反序列化。
序列化畢竟是一個 IO 操作,在優化性能的場景,我們就可以基於實際業務場景和需求出發,減少非必要的序列和反序列操作,尤其是對一些比較打的對象。需要注意的是,deserialize 這個值只有把註解打在方法上時才是有效的(這點可以從其源碼看到)。
最後再說一個使用 fastjson 最最常見的問題,關於默認構造函數的問題。
我們知道一個普通的 java 類,如果沒有定義構造函數的話,編譯器會幫我們自定生成一個構造函數。但是如果我們自己定義了構造函數,那麼默認的構造函數就沒了。
這個時候如果我們直接解析 Json 解析,會拋出異常。 com.alibaba.fastjson.JSONException: default constructor not found
至於具體原因,看一下源碼也很容易理解了。這個時候,就只能把默認的構造加上了。
而在使用 Kotlin 的場景,也是存在同樣的問題。
現在大家都習慣使用 data class 定義數據類。雖然這樣定義的類型,從反編譯的結果看似乎是存在默認構造函數的,但依舊會報錯。
可以看到是有存在構造函數的,但是依舊會產生問題。對於 Kotlin 的場景,我們用兩種解決辦法。
這樣依舊不解決問題。
to be continued ...
本文從 Json 解析常規用法出發,解讀了對 Map 這種 Json 數據類型的解析。從中可以學習到,有時候我們在面臨一些問題是會一籌莫展,會出現非常規的場景。這個時候,就需要我們從問題的本質出發,看透問題的根源,一層層抽絲剝縷的去解決。
問題總是會不斷出現的,重要的是在我們解決完問題之後不僅要學會解決方法,更要學會解決問題的思路。
『貳』 如何構建json串,並將map轉為jsonObject對象的三種方式(scala)
眾所周知,kafka中存儲的數據是經過BASE64加密後的jsonObject,因此從kafka中讀取的數據經過base64解碼,得到的是json串,利用JSONObect的方法可以對json串進行解析,拿到對應的數據。那麼要如何將scala對象或者java對象轉換為JsonObject對象或JSONObject對象呢?(注意:JsonObject對象和JSONObject對象不同,調用的API也不一樣)
三種轉換方式依賴的包源碼都是用JAVA編寫,所以構建Map對象時完全使用java對象,不會發生錯誤。構建過程如下:
三種將java對象轉換為jsonObject對象的開源包有:
1、google提供的Genson是一個完全的Java和JSON轉換的類庫,提供了全面的數據綁定、流操作等。基於Apache 2.0協議發布。轉換結果為
JsonObject對象。
使用需要先導入Jar包:import com.google.gson.{Gson, JsonParser}
引入依賴:這里選用版本為:2.2.4,具體版本可以根據業務需求選擇。
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
2、Fastjson 是一個 Java 庫,可以將 Java 對象轉換為 JSON 格式,當然它也可以將 JSON 字元串轉換為 Java 對象。
導入jar包:import com.alibaba.fastjson.JSON
引入依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.8</version>
</dependency>
3、net.sf.json-lib方式
導入jar包:import net.sf.json.JSONObject
引入依賴:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib-ext-spring</artifactId>
<version>1.0.2</version>
</dependency>
『叄』 fastjson怎樣json轉換成字元串
// jackson
private static ObjectMapper om = new ObjectMapper ();
public static String objectToString (Object obj ) throws IOException{
return om.writeValueAsString (obj );
}
@Test
public void test1 () throws IOException {
Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> map2 = new HashMap<String, String>();
map2.put ("name", "1");
map2.put ("age", "12");
map.put ("att", map2 );
List<String> list = new ArrayList<String>();
list.add ("hi");list.add ("hello");
map.put ("list", list );
List<Map<String, String>> confuselist = new ArrayList<Map<String, String>>();
Map<String, String> map3 = new HashMap<String, String>();
map3.put ("name", "1");
map3.put ("age", "12");
confuselist.add (map3 );
confuselist.add (map2 );
map.put ("confuselist", confuselist );
Object array = Array.newInstance (String.class, 10 );
Array.set (array, 0, "a");
Array.set (array, 1, "b");
Array.set (array, 2, "c");
map.put ("array", array );
// 使用 jackson
System.out.println (objectToString (map ));
// 使用 fastJson
System.out.println (JSON.toJSONString (map ));
}
輸出:
{"att":{"age":"12","name":"1"},"list":["hi","hello"],"confuselist":[{"age":"12","name":"1"}, {"age":"12","name":"1"}],"array":["a","b","c",null,null,null,null,null,null,null]}
{"att":{"age":"12","name":"1"},"list":["hi","hello"],"confuselist":[{"age":"12","name":"1"},{"$ref":"$.att"}],"array":["a","b","c",null,null,null,null,null,null,null]}
『肆』 fastjson中怎麼把java對象轉化為json對象
寫入以下代碼即可實現:
public static void main(String[] args) {
User_DAL userDal = new User_DAL();// 創建數據訪問對象
ResponseResult<User> ret = userDal.getUserList("id < 50", 2, 10);// 查詢ID小於50的用戶,保存版到分頁類中
String json = JSON.toJSONString(ret, true); // 將對象轉換成json字元權串,true為格式化輸出
System.out.println(json);
List<User> list = JSON.parseArray("{{name:123},{name:456}}", User.class);//將json字元串,轉換成Java對象數組
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName());
}
}
『伍』 FastJson和Json以及@ResponseBody
@Restcontroller是@Controller和@ResponseBody的結合體,將後台返回的Java對象轉換為Json字元串傳遞給前台。它是springmvc通過配置實現的,spring默認帶的轉json包為jackson,因為fastJson比較快一般會引入fastjson來替換。
解決bean與json欄位不一致問題,或者欄位定義不符合前端所需岩租要的標准,需要使用@JsonProperty和@JSONField註解粗橡兆。
@jsonProperty是Jackson的包,@JSONproperty這個註解用於屬性上面
而@jsonfield是如鏈fastjson的包,@JSONField這個註解可以用於get、set以及屬性上面@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")是時間的格式化,可以用於get、set以及屬性上面
FastJson是阿里巴巴的開源JSON解析庫,它可以解析JSON格式的字元串,支持將Java Bean序列化為JSON字元串,也可以從JSON字元串反序列化到JavaBean。FastJson的API十分簡潔,FastJson重要的類為JSONObject,經常調用的方法如下:
public static final Object parse(String text); // 把JSON文本parse為JSONObject或者JSONArray
public static final JSONObject parseObject(String text); // 把JSON文本parse成JSONObject
public static final T parseObject(String text, Class clazz); // 把JSON文本parse為JavaBean
public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray
public static final List parseArray(String text, Class clazz); //把JSON文本parse成JavaBean集合
public static final String toJSONString(Object object); // 將JavaBean序列化為JSON文本public static final String toJSONString(Object object, boolean prettyFormat); // 將JavaBean序列化為帶格式的JSON文本
public static final Object toJSON(Object javaObject); 將JavaBean轉換為JSONObject或者JSONArray。
Jackson相對來說比較高效的Json類庫,在項目中主要使用Jackson進行JSON和Java對象轉換,Jackson ObjectMapper類是使用Jackson解析JSON最簡單的方法。可以從字元串、流或文件解析JSON,並創建Java對象或對象圖來表示已解析的JSON。將JSON解析為Java對象也稱為從JSON反序列化Java對象
1.JAVA對象轉JSON
ObjectMapper mapper = new ObjectMapper();
String bjectMapper = mapper.writeValueAsString(obj);
2.JSON轉Java類[JSON反序列化]
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> inMap = mapper.readValue(jsonStr, HashMap.class);
『陸』 fastjson是怎麼實現JSON的序列化和反序列化的
反序列化源函數
· parseObject
-將 json字元串 反序列化為 java.class
@sherineZJU
List<T> temp= JSON.parseObject(fastjson,T.class);
//transform the json to T123123
-fastjson 為 json格式的字元串(String類型)
-T 為 與 json格式對應的 自定義 java.class。
· parseObject
-將 json字元串 反序列化為 java.util.List
@sherineZJU
List<T> oldk = JSONArray.parseArray(fastjson,T.class);
//transform the json to List<T>123123
-fastjson 為 json格式的字元串(String類型)
-List< T> 為 與 json格式對應的 自定義 java.util.List。
java.class 與 json字元串 的對應關系
注意 json字元串 的關鍵字一定要與 java.class 中的對應變數名相同。