Json解析之Gson庫

鴨脖發表於2015-04-21

Json(JavaScript Object Notation)是一種輕量級的資料交換格式,類似XML,但比XML更小更快更容易解析。當前各種流行的web應用框架都對Json提供良好的支援,各種流行開發語言也支援Json解析。

 

Java中解析Json的方式也很多,根據官方的JSONObject庫,自己設計的一個抽象工具類:

 

Java程式碼  收藏程式碼
  1. import java.io.Serializable;  
  2. import java.util.List;  
  3.   
  4. import org.json.JSONException;  
  5. import org.json.JSONObject;  
  6.   
  7. public abstract class JsonParser <T extends Serializable>{  
  8.       
  9.     abstract List<T> getListFromJson(String str);  
  10.       
  11.     abstract T getObjectFromJson(JSONObject jobj);  
  12.       
  13.     public T getObjectFromJson(String str) {  
  14.         try {  
  15.             JSONObject jsonObject = new JSONObject(str);  
  16.             return getObjectFromJson(jsonObject);  
  17.         } catch (JSONException e) {  
  18.             e.printStackTrace();   
  19.         } catch(Exception e){  
  20.             e.printStackTrace();  
  21.         }  
  22.         return null;  
  23.     }  
  24.       
  25.     protected String getValueByName(JSONObject jobj, String name)  
  26.             throws JSONException{  
  27.         if(jobj.has(name)){  
  28.             return jobj.getString(name);  
  29.         }  
  30.         return null;  
  31.     }  
  32.       
  33. }  

 

具體實現的子類如下:

 

Java程式碼  收藏程式碼
  1. public class UserInfoParser extends JsonParser<UserInfo> {  
  2.   
  3.     private UserInfoParser() {  
  4.           
  5.     }  
  6.       
  7.     @Override  
  8.     List<UserInfo> getListFromJson(String str) {  
  9.         try {  
  10.             JSONArray array = new JSONArray(str);  
  11.             int len = array.length();  
  12.             ArrayList<UserInfo> list = new ArrayList<UserInfo>(len);  
  13.             for(int i=0;i<len;i++) {  
  14.                 UserInfo info = getObjectFromJson(array.getJSONObject(i));  
  15.                 list.add(info);  
  16.             }  
  17.             return list;  
  18.         } catch (JSONException e) {  
  19.             e.printStackTrace();  
  20.         }  
  21.         return null;  
  22.     }  
  23.   
  24.     @Override  
  25.     UserInfo getObjectFromJson(JSONObject jobj) {  
  26.         try {  
  27.             UserInfo info = new UserInfo();  
  28.             info.setId(getValueByName(jobj, UserInfo.NODE_ID));  
  29.             info.setFace(getValueByName(jobj,UserInfo.NODE_FACE));  
  30.             info.setUsername(getValueByName(jobj,UserInfo.NODE_USER_NAME));  
  31.             return info;  
  32.         } catch (JSONException e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.         return null;  
  36.     }  
  37.   
  38. }  

 

當泛型值物件T,對應的資料結構比較簡單,層次比較少的時候,官方的JSONObject庫解析還過得去。當遇到層次較多(Json裡面包含N個Json陣列),資料結構複雜(Json由對個複雜資料的Json組成)的Json,解析速度就會大大降低!

 

在處理複雜Json結構時,我推薦使用Google的Gson解析庫。剛剛接觸Gson時,我有以下疑慮:

1、Gson對Json的支援度如何,能不能支援所有的Json結構?

2、由於Gson是基於Java的反射原理來實現的,解析的效率如何保證?

3、上手難度如何?

 

當我在專案實驗性地引入Gson後,我o嘴了~~真不愧是Google出品,實屬佳品!

 

再我的專案是基於android平臺的App,使用Gson之前,不僅http請求和Json資料解析的耗時太長,而且記憶體佔有一直居高不下。

使用Gson後,解析的時間縮短了30%(這只是Json的解析時間,不算上http請求的時間),記憶體佔用足足減少了一半!!!最重要的是,開發效率還提高不少,何以見得,請看:

 

1、值物件必須實現序列化介面,成員屬性的名稱必須與Json資料的key一致,建議遵從J2EE的標準,使用get-set方法控制屬性的訪問,因為Json的key是後臺應用定義的,假如後臺與前臺的開發語言不同,命名規範也不一致,使用get-set能有效分離這些不規範的命名到其他模組程式碼中去。

 

 

Java程式碼  收藏程式碼
  1. public class UserInfo implements Serializable {  
  2.   
  3.     private static final long serialVersionUID = 1050128890144400614L;  
  4.   
  5.     private String id;  
  6.     private String username;  
  7.     private String face;  
  8.   
  9.     public String getId() {  
  10.         return id;  
  11.     }  
  12.   
  13.     public void setId(String id) {  
  14.         this.id = id;  
  15.     }  
  16.   
  17.     public String getUsername() {  
  18.         return username;  
  19.     }  
  20.   
  21.     public void setUsername(String username) {  
  22.         this.username = username;  
  23.     }  
  24.   
  25.     public String getFace() {  
  26.         return face;  
  27.     }  
  28.   
  29.     public void setFace(String face) {  
  30.         this.face = face;  
  31.     }  
  32.   
  33. }  

 

 

2、奉上一個基於Gson的Json解析封裝工具:

 

Java程式碼  收藏程式碼
  1. /** 
  2.  * Gson類庫的封裝工具類,專門負責解析json資料</br> 
  3.  * 內部實現了Gson物件的單例 
  4.  * @author zhiweiofli 
  5.  * @version 1.0 
  6.  * @since 2012-9-18 
  7.  */  
  8. public class JsonUtil {  
  9.   
  10.     private static Gson gson = null;  
  11.       
  12.     static {  
  13.         if (gson == null) {  
  14.             gson = new Gson();  
  15.         }  
  16.     }  
  17.   
  18.     private JsonUtil() {  
  19.       
  20.     }  
  21.   
  22.     /** 
  23.      * 將物件轉換成json格式 
  24.      *  
  25.      * @param ts 
  26.      * @return 
  27.      */  
  28.     public static String objectToJson(Object ts) {  
  29.         String jsonStr = null;  
  30.         if (gson != null) {  
  31.             jsonStr = gson.toJson(ts);  
  32.         }  
  33.         return jsonStr;  
  34.     }  
  35.   
  36.     /** 
  37.      * 將物件轉換成json格式(並自定義日期格式) 
  38.      *  
  39.      * @param ts 
  40.      * @return 
  41.      */  
  42.     public static String objectToJsonDateSerializer(Object ts,  
  43.             final String dateformat) {  
  44.         String jsonStr = null;  
  45.         gson = new GsonBuilder()  
  46.                 .registerTypeHierarchyAdapter(Date.class,  
  47.                         new JsonSerializer<Date>() {  
  48.                             public JsonElement serialize(Date src,  
  49.                                     Type typeOfSrc,  
  50.                                     JsonSerializationContext context) {  
  51.                                 SimpleDateFormat format = new SimpleDateFormat(  
  52.                                         dateformat);  
  53.                                 return new JsonPrimitive(format.format(src));  
  54.                             }  
  55.                         }).setDateFormat(dateformat).create();  
  56.         if (gson != null) {  
  57.             jsonStr = gson.toJson(ts);  
  58.         }  
  59.         return jsonStr;  
  60.     }  
  61.   
  62.     /** 
  63.      * 將json格式轉換成list物件 
  64.      *  
  65.      * @param jsonStr 
  66.      * @return 
  67.      */  
  68.     public static List<?> jsonToList(String jsonStr) {  
  69.         List<?> objList = null;  
  70.         if (gson != null) {  
  71.             java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken<List<?>>() {  
  72.             }.getType();  
  73.             objList = gson.fromJson(jsonStr, type);  
  74.         }  
  75.         return objList;  
  76.     }  
  77.       
  78.     /** 
  79.      * 將json格式轉換成list物件,並準確指定型別 
  80.      * @param jsonStr 
  81.      * @param type 
  82.      * @return 
  83.      */  
  84.     public static List<?> jsonToList(String jsonStr, java.lang.reflect.Type type) {  
  85.         List<?> objList = null;  
  86.         if (gson != null) {  
  87.             objList = gson.fromJson(jsonStr, type);  
  88.         }  
  89.         return objList;  
  90.     }  
  91.   
  92.     /** 
  93.      * 將json格式轉換成map物件 
  94.      *  
  95.      * @param jsonStr 
  96.      * @return 
  97.      */  
  98.     public static Map<?, ?> jsonToMap(String jsonStr) {  
  99.         Map<?, ?> objMap = null;  
  100.         if (gson != null) {  
  101.             java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken<Map<?, ?>>() {  
  102.             }.getType();  
  103.             objMap = gson.fromJson(jsonStr, type);  
  104.         }  
  105.         return objMap;  
  106.     }  
  107.   
  108.     /** 
  109.      * 將json轉換成bean物件 
  110.      *  
  111.      * @param jsonStr 
  112.      * @return 
  113.      */  
  114.     public static Object jsonToBean(String jsonStr, Class<?> cl) {  
  115.         Object obj = null;  
  116.         if (gson != null) {  
  117.             obj = gson.fromJson(jsonStr, cl);  
  118.         }  
  119.         return obj;  
  120.     }  
  121.   
  122.     /** 
  123.      * 將json轉換成bean物件 
  124.      *  
  125.      * @param jsonStr 
  126.      * @param cl 
  127.      * @return 
  128.      */  
  129.     @SuppressWarnings("unchecked")  
  130.     public static <T> T jsonToBeanDateSerializer(String jsonStr, Class<T> cl,  
  131.             final String pattern) {  
  132.         Object obj = null;  
  133.         gson = new GsonBuilder()  
  134.                 .registerTypeAdapter(Date.classnew JsonDeserializer<Date>() {  
  135.                     public Date deserialize(JsonElement json, Type typeOfT,  
  136.                             JsonDeserializationContext context)  
  137.                             throws JsonParseException {  
  138.                         SimpleDateFormat format = new SimpleDateFormat(pattern);  
  139.                         String dateStr = json.getAsString();  
  140.                         try {  
  141.                             return format.parse(dateStr);  
  142.                         } catch (ParseException e) {  
  143.                             e.printStackTrace();  
  144.                         }  
  145.                         return null;  
  146.                     }  
  147.                 }).setDateFormat(pattern).create();  
  148.         if (gson != null) {  
  149.             obj = gson.fromJson(jsonStr, cl);  
  150.         }  
  151.         return (T) obj;  
  152.     }  
  153.   
  154.     /** 
  155.      * 根據 
  156.      *  
  157.      * @param jsonStr 
  158.      * @param key 
  159.      * @return 
  160.      */  
  161.     public static Object getJsonValue(String jsonStr, String key) {  
  162.         Object rulsObj = null;  
  163.         Map<?, ?> rulsMap = jsonToMap(jsonStr);  
  164.         if (rulsMap != null && rulsMap.size() > 0) {  
  165.             rulsObj = rulsMap.get(key);  
  166.         }  
  167.         return rulsObj;  
  168.     }  
  169.   
  170. }  

 

引用方式十分簡單:

 

Java程式碼  收藏程式碼
  1. (UserInfo)JsonUtil.jsonToBean(jsonString, UserInfo.class);  

 

3、解析複雜Json的方式

Gson支援解析多層結構的Json,當然對於多層解析的效率,暫時還沒測試過,估計效率下降不會超過JSONObject...

想解析Json中的Json,Json中的Json陣列,Gson提供InstanceCreator結構,來例項化對應的物件,用來載入已解析的json資料。估計解析的流程是,Gson反射屬性名稱前,先考量能否獲得其對應的例項,再對屬性物件進行反射、賦值,如此迭代進行...

 

例如,解析Json陣列的方式,實現:

 

Java程式碼  收藏程式碼
  1. public class UserInfoResult extends ResponseState implements InstanceCreator<List<UserInfo>>{  
  2.   
  3.     private static final long serialVersionUID = -8701527648781449574L;  
  4.       
  5.     public List<UserInfo> userlist;  
  6.   
  7.     @Override  
  8.     public List<UserInfo> createInstance(Type arg0) {  
  9.         return new ArrayList<UserInfo>(2);  
  10.     }  
  11. }  

 

對比JSONObject,Gson的好處在於:

1、高效,安全的反射,帶來高效的解析速度

2、簡化的開發流程,對比JSONObject每次都要設計解析的物件,Gson只需要設計值物件,由此帶來的就是敏捷的開發

3、良好的支援,Gson屬於開源專案,專案位於http://code.google.com/p/google-gson/,現在版本還在不斷升級中,建議使用最新的穩定版。

 

最後,本文只對比介紹了Gson對Json解析的方面,對於Json的自動化生成,註釋的使用,容以後再分享...

相關文章