Json(JavaScript Object Notation)是一種輕量級的數據交換格式,類似XML,但比XML更小更快更容易解析。當前各種流行的web應用框架都對Json提供良好的支持,各種流行開發語言也支持Json解析。
Java中解析Json的方式也很多,根據官方的JSONObject庫,自己設計的一個抽象工具類:
import java.io.Serializable;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
public abstract class JsonParser <T extends Serializable>{
abstract List<T> getListFromJson(String str);
abstract T getObjectFromJson(JSONObject jobj);
public T getObjectFromJson(String str) {
try {
JSONObject jsonObject = new JSONObject(str);
return getObjectFromJson(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
return null;
}
protected String getValueByName(JSONObject jobj, String name)
throws JSONException{
if(jobj.has(name)){
return jobj.getString(name);
}
return null;
}
}
具體實現的子類如下:
public class UserInfoParser extends JsonParser<UserInfo> {
private UserInfoParser() {
}
@Override
List<UserInfo> getListFromJson(String str) {
try {
JSONArray array = new JSONArray(str);
int len = array.length();
ArrayList<UserInfo> list = new ArrayList<UserInfo>(len);
for(int i=0;i<len;i++) {
UserInfo info = getObjectFromJson(array.getJSONObject(i));
list.add(info);
}
return list;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
UserInfo getObjectFromJson(JSONObject jobj) {
try {
UserInfo info = new UserInfo();
info.setId(getValueByName(jobj, UserInfo.NODE_ID));
info.setFace(getValueByName(jobj,UserInfo.NODE_FACE));
info.setUsername(getValueByName(jobj,UserInfo.NODE_USER_NAME));
return info;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
當泛型值對象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能有效分離這些不規範的命名到其他模塊代碼中去。
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1050128890144400614L;
private String id;
private String username;
private String face;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFace() {
return face;
}
public void setFace(String face) {
this.face = face;
}
}
2、奉上一個基於Gson的Json解析封裝工具:
/**
* Gson類庫的封裝工具類,專門負責解析json數據</br>
* 內部實現了Gson對象的單例
* @author zhiweiofli
* @version 1.0
* @since 2012-9-18
*/
public class JsonUtil {
private static Gson gson = null;
static {
if (gson == null) {
gson = new Gson();
}
}
private JsonUtil() {
}
/**
* 將對象轉換成json格式
*
* @param ts
* @return
*/
public static String objectToJson(Object ts) {
String jsonStr = null;
if (gson != null) {
jsonStr = gson.toJson(ts);
}
return jsonStr;
}
/**
* 將對象轉換成json格式(並自定義日期格式)
*
* @param ts
* @return
*/
public static String objectToJsonDateSerializer(Object ts,
final String dateformat) {
String jsonStr = null;
gson = new GsonBuilder()
.registerTypeHierarchyAdapter(Date.class,
new JsonSerializer<Date>() {
public JsonElement serialize(Date src,
Type typeOfSrc,
JsonSerializationContext context) {
SimpleDateFormat format = new SimpleDateFormat(
dateformat);
return new JsonPrimitive(format.format(src));
}
}).setDateFormat(dateformat).create();
if (gson != null) {
jsonStr = gson.toJson(ts);
}
return jsonStr;
}
/**
* 將json格式轉換成list對象
*
* @param jsonStr
* @return
*/
public static List<?> jsonToList(String jsonStr) {
List<?> objList = null;
if (gson != null) {
java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken<List<?>>() {
}.getType();
objList = gson.fromJson(jsonStr, type);
}
return objList;
}
/**
* 將json格式轉換成list對象,並準確指定類型
* @param jsonStr
* @param type
* @return
*/
public static List<?> jsonToList(String jsonStr, java.lang.reflect.Type type) {
List<?> objList = null;
if (gson != null) {
objList = gson.fromJson(jsonStr, type);
}
return objList;
}
/**
* 將json格式轉換成map對象
*
* @param jsonStr
* @return
*/
public static Map<?, ?> jsonToMap(String jsonStr) {
Map<?, ?> objMap = null;
if (gson != null) {
java.lang.reflect.Type type = new com.google.gson.reflect.TypeToken<Map<?, ?>>() {
}.getType();
objMap = gson.fromJson(jsonStr, type);
}
return objMap;
}
/**
* 將json轉換成bean對象
*
* @param jsonStr
* @return
*/
public static Object jsonToBean(String jsonStr, Class<?> cl) {
Object obj = null;
if (gson != null) {
obj = gson.fromJson(jsonStr, cl);
}
return obj;
}
/**
* 將json轉換成bean對象
*
* @param jsonStr
* @param cl
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T jsonToBeanDateSerializer(String jsonStr, Class<T> cl,
final String pattern) {
Object obj = null;
gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
SimpleDateFormat format = new SimpleDateFormat(pattern);
String dateStr = json.getAsString();
try {
return format.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}).setDateFormat(pattern).create();
if (gson != null) {
obj = gson.fromJson(jsonStr, cl);
}
return (T) obj;
}
/**
* 根據
*
* @param jsonStr
* @param key
* @return
*/
public static Object getJsonValue(String jsonStr, String key) {
Object rulsObj = null;
Map<?, ?> rulsMap = jsonToMap(jsonStr);
if (rulsMap != null && rulsMap.size() > 0) {
rulsObj = rulsMap.get(key);
}
return rulsObj;
}
}
引用方式十分簡單:
(UserInfo)JsonUtil.jsonToBean(jsonString, UserInfo.class);
3、解析複雜Json的方式
Gson支持解析多層結構的Json,當然對於多層解析的效率,暫時還沒測試過,估計效率下降不會超過JSONObject...
想解析Json中的Json,Json中的Json數組,Gson提供InstanceCreator結構,來實例化對應的對象,用來加載已解析的json數據。估計解析的流程是,Gson反射屬性名稱前,先考量能否獲得其對應的實例,再對屬性對象進行反射、賦值,如此迭代進行...
例如,解析Json數組的方式,實現:
public class UserInfoResult extends ResponseState implements InstanceCreator<List<UserInfo>>{
private static final long serialVersionUID = -8701527648781449574L;
public List<UserInfo> userlist;
@Override
public List<UserInfo> createInstance(Type arg0) {
return new ArrayList<UserInfo>(2);
}
}
對比JSONObject,Gson的好處在於:
1、高效,安全的反射,帶來高效的解析速度
2、簡化的開發流程,對比JSONObject每次都要設計解析的對象,Gson只需要設計值對象,由此帶來的就是敏捷的開發
3、良好的支持,Gson屬於開源項目,項目位於http://code.google.com/p/google-gson/,現在版本還在不斷升級中,建議使用最新的穩定版。