如今的代碼開發中,json這種數據類型使用的是愈來愈多,由於它的存取速度都比較快,並且,使用起來很是的簡單,今天工做的時候,我就遇到了一個關於json的生產問題,這個問題我以前確實尚未注意過,這邊記錄下。java
再一次遠程調用獲取相關信息成功以後,須要解析返回的json對象,這個json裏面包含了三個元素,一個key爲data的jsonObject,表示業務數據,一個Key爲success的String,表示是否成功,一個key爲resultMessage的失敗緣由。正常狀況下,這個data是不可能爲空的,可是今天不知道怎麼了,遠端返回的結果裏面這個data就是空的,因此解析的時候就出現了以下異常:json
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to com.alibaba.fastjson.JSONObject at com.alibaba.fastjson.JSONObject.getJSONObject(JSONObject.java:109) at com.example.demo.MainTest.main(MainTest.java:10)
固然這裏要提早說明下,我這邊使用的fastJson的版本是1.2.7,出現上面這個錯是否是很奇怪,正常不該該返回一個null嗎?怎麼返回的是String類型不能轉成JSONObject呢?app
問題到了這個地步還有什麼好說的呢?只能模仿生產的返回,一步一步的去解析了。測試
1 public class MainTest { 2 public static void main(String[] args) {
// 寫一個字符串,模擬生產的返回,其中data的值爲空 3 String str = "{\"data\": \"\",\"success\": \"true\",\"resultMessage\": \"成功\"}"; 4 // 序列化成json 5 JSONObject result = JSONObject.parseObject(str);
// 獲取data的值 6 JSONObject data = result.getJSONObject("data"); 7 8 System.out.println(data); 9 } 10 }
經過debug能夠得知,第五行代碼是能夠正常執行的,返回以下:spa
{"data":"","success":"true","resultMessage":"成功"}debug
這個沒有問題,那問題就在第6行代碼上了,咱們看一下getJSONObject方法:code
1 public JSONObject getJSONObject(String key) { 2 Object value = map.get(key); 3 4 if (value instanceof JSONObject) { 5 return (JSONObject) value; 6 } 7 8 return (JSONObject) toJSON(value); 9 }
這邊第2行代碼根據key獲取的value是"",這個顯然不是JSONObject類型,直接走最後一行toJSON方法,對象
1 public static Object toJSON(Object javaObject, ParserConfig mapping) { 2 if (javaObject == null) { 3 return null; 4 } 5 6 if (javaObject instanceof JSON) { 7 return javaObject; 8 } 9 10 if (javaObject instanceof Map) { 11 Map<Object, Object> map = (Map<Object, Object>) javaObject; 12 13 JSONObject json = new JSONObject(map.size()); 14 15 for (Map.Entry<Object, Object> entry : map.entrySet()) { 16 Object key = entry.getKey(); 17 String jsonKey = TypeUtils.castToString(key); 18 Object jsonValue = toJSON(entry.getValue()); 19 json.put(jsonKey, jsonValue); 20 } 21 22 return json; 23 } 24 25 if (javaObject instanceof Collection) { 26 Collection<Object> collection = (Collection<Object>) javaObject; 27 28 JSONArray array = new JSONArray(collection.size()); 29 30 for (Object item : collection) { 31 Object jsonValue = toJSON(item); 32 array.add(jsonValue); 33 } 34 35 return array; 36 } 37 38 Class<?> clazz = javaObject.getClass(); 39 40 if (clazz.isEnum()) { 41 return ((Enum<?>) javaObject).name(); 42 } 43 44 if (clazz.isArray()) { 45 int len = Array.getLength(javaObject); 46 47 JSONArray array = new JSONArray(len); 48 49 for (int i = 0; i < len; ++i) { 50 Object item = Array.get(javaObject, i); 51 Object jsonValue = toJSON(item); 52 array.add(jsonValue); 53 } 54 55 return array; 56 } 57 58 if (mapping.isPrimitive(clazz)) { 59 return javaObject; 60 } 61 62 try { 63 List<FieldInfo> getters = TypeUtils.computeGetters(clazz, null); 64 65 JSONObject json = new JSONObject(getters.size()); 66 67 for (FieldInfo field : getters) { 68 Object value = field.get(javaObject); 69 Object jsonValue = toJSON(value); 70 71 json.put(field.getName(), jsonValue); 72 } 73 74 return json; 75 } catch (IllegalAccessException e) { 76 throw new JSONException("toJSON error", e); 77 } catch (InvocationTargetException e) { 78 throw new JSONException("toJSON error", e); 79 } 80 }
這個方法有點長,但其實,真正執行了的也就是38行,獲取value對應的class對象,這邊返回的java.lang.String,再就是58到60行,判斷這個對象是否是基礎類型,是就直接返回,那麼這邊就返回的"",後面強制類型轉換的時候固然就會報錯。blog
上面這個問題彷佛還很差解決啊,後來看了一下fastJson的幾個高版本,已經解決了這個問題,咱們來看一下1.2.51的getJSONObject方法:開發
1 public JSONObject getJSONObject(String key) { 2 Object value = map.get(key); 3 4 if (value instanceof JSONObject) { 5 return (JSONObject) value; 6 } 7 8 if (value instanceof String) { 9 return JSON.parseObject((String) value); 10 } 11 12 return (JSONObject) toJSON(value); 13 }
多了8-10行代碼,針對String作了下處理,直接返回String解析以後的結果,這樣就能夠返回理想中的null了。
平時代碼開發過程當中,必定要進行異常狀況的測試,不可以想固然,要儘可能覆蓋每一個分支,要讓代碼跑不崩潰。