Gson&FastJson解析异常Json的处理
这几天因为开发需求对项目中Json的解析做了一下整理。在整理的过程中遇到比较大的问题,就是后端没按约定返回字段值,以及空字符串(”“、“null”)等情况。某度和某哥了一下,发现遇到这个问题的朋友还是挺多的。于是趁热打铁总结了一下解决方案奉献给大家。 Gson和FastJson的恩怨情仇FastJson是阿里开源的一个Json解析项目,其内部使用了各种方案使得Json序列化和反序列化的速度提升到了极致。而Gson则是Google开源的,据说可以解析一些FastJson解析不了的超复杂json结构(这个本人也没实际验证过,欢迎大家亲自去实践检验),解析速度相对要慢些。 { "DaTa": "android" }
private String data;
而在序列化的时候,则默认又是会将首字母置为小写。如下 private String Data;
会序列化成 {“data”: "android" }
当然,这个问题可以用@JSONField注解来解决 @JSONField(name = "Data")
private String data; 注意这里要小写开头
则会序列化成 {“Data”: "android" }
而相对于Gson,则完全是对字段名大小写敏感的,无论是序列化还是反序列化。也就是说,如果我们之前的模型没注意大小写的规范,用FastJson将后台json解析成前台对象时,是完全没问题的;而如果换成Gson则有可能解析失败。 异常情况假设我们和后端约定Json数据格式如下: { "code":1 ,"msg":"成功" ,"Data":{"id":1,"name":"王小二" } }
{ "code":1 ,"Data":[{"id":1,"name":"王小二" },{"id":2,"name":"马大三" }] }
于是数据模型就可以这样定义: /** * HttpResult.java */
public class HttpResult<T> {
private int code;
private String msg;
private T Data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return Data;
}
public void setData(T data) {
Data = data;
}
}
/** * UserInfo.java */
public class UserInfo {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
解析过程就像下面这么写。其中,JsonParseUtil是封装的Json解析工具类,文章最后会有全部源码;GenericType则是为了统一FastJson和Gson两个库对泛型解析的通用类,和FastJson的TypeReference、Gson的TypeToken类似,都是通过ParameterizedType来获取泛型类型指定的实际类型。 HttpResult<UserInfo> httpResult = JsonParseUtil.parseToGenericObject(jsonStr,new GenericType<HttpResult<UserInfo>>(){});
/** * JsonParseUtil.java */
public static <T> T parseToGenericObject(String dataStr,GenericType<T> genericType) {
if (TextUtils.isEmpty(dataStr)) {
return null;
}
//Gson解析
/*T t = getSingleton().fromJson(dataStr,genericType.getType());*/
//FastJson解析
T t = JSON.parSEObject(dataStr,genericType.getType());
return t;
}
一切似乎都那么顺其自然、一切似乎都那么的简单……噢耶!提交代码,准备下班了! 情景1-定义整型字段,返回字符串“”后台返回如下: { "code":1 ,"Data":{"id":"","name":"" } }
属性id是定义了int类型的,却返回了空字符串“”. /** * IntegerGsonDeserializer.java */
public class IntegerGsonDeserializer implements JsonDeserializer<Integer> {
@Override
public Integer deserialize(JsonElement jsonElement,Type type,JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
try {
//默认后台返回"" 或者 "null",则设置默认值为 0
if (jsonElement.getAsString().equals("") || jsonElement.getAsString().equals("null")) {
return 0;
}
} catch (Exception e) {
}
try {
return jsonElement.getAsInt();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
}
并且我们在程序最开始注册使用以上自定义反序列化的类型 /** * Application.java */
JsonParseUtil.setSingletonInstance(
new GsonBuilder()
.registerTypeAdapter(Integer.class,new IntegerGsonDeserializer())
.registerTypeAdapter(int.class,new IntegerGsonDeserializer())
.create());
情景2-泛型Data无数据时,返回空字符串”“后台返回如下: { "code":1 ,"Data":"" }
这是由于泛型Data实际上是一个Json对象或者数组,而在Json里面空字符串不属于Json对象导致的解析出错,所以返回的Data必须是{}或者[]。 /** * HttpResultGsonDeserializer.java */
public class HttpResultGsonDeserializer implements JsonDeserializer<HttpResult<?>> {
@Override
public HttpResult deserialize(JsonElement jsonElement,JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonElement jsonData = jsonObject.has("Data") ? jsonObject.get("Data") : null;
HttpResult httpResult = new HttpResult();
httpResult.setReturnCode(jsonObject.has("code") ? jsonObject.get("code").getAsInt() : 0);
httpResult.setReturnMessage(jsonObject.has("msg") ? jsonObject.get("msg").getAsString() : "");
//处理Data空串情况
if(jsonData != null && jsonData.isJsonObject()) {
//指定泛型具体类型
if (type instanceof ParameterizedType) {
Type itemType = ((ParameterizedType) type).getActualTypeArguments()[0];
Object item = jsonDeserializationContext.deserialize(jsonData,itemType);
httpResult.setData(item);
}else{
//未指定泛型具体类型
httpResult.setData(jsonData);
}
}else {
httpResult.setData(null);
}
return httpResult;
}
}
在FastJson中,也提供了相应的接口ObjectDeserializer,可以给我们自定义反序列化操作。 /** * HttpResultFJsonDeserializer.java */
public class HttpResultFJsonDeserializer implements ObjectDeserializer {
@Override
public <T> T deserialze(DefaultJSONParser parser,Object fieldName) {
Map map = parser.parSEObject(Map.class);
HttpResult httpResult = new HttpResult();
httpResult.setReturnCode(map.containsKey("code") ? (int)map.get("code") : 0);
httpResult.setReturnMessage(map.containsKey("msg") ? String.valueOf(map.get("msg")) : "");
//处理Data空串情况
if(map.containsKey("Data") && !(map.get("Data") instanceof String)) {
//指定泛型具体类型
if (type instanceof ParameterizedType) {
Type itemType = ((ParameterizedType) type).getActualTypeArguments()[0];
Object item = JSON.parSEObject(String.valueOf(map.get("Data")),itemType);
httpResult.setData(item);
}else{
//未指定泛型具体类型
httpResult.setData(map.get("Data"));
}
}else {
httpResult.setData(null);
}
return (T) httpResult;
}
@Override
public int getFastMatchToken() {
return 0;
}
}
同样,我们在Application里面进行注册。 /** * Application.java */
JsonParseUtil.setSingletonInstance(
new GsonBuilder()
.registerTypeAdapter(HttpResult.class,new HttpResultGsonDeserializer())
.create());
FastJson的注册方式 /** * Application.java */
ParserConfig.getGlobalInstance()
.putDeserializer(HttpResult.class,new HttpResultFJsonDeserializer());
Gson & FastJson 封装源码JsonParseUtil 工具类,其中注释部分为Gson实现,可自己选择。 /** * JsonParseUtil.java */
public class JsonParseUtil {
/** * Gson 本身线程安全 * 直接采用“懒汉方式”单例写法 */
private static Gson singleton;
private static Gson getSingleton() {
if (singleton == null) {
singleton = new Gson();
}
return singleton;
}
/** * 定制Gson * 使用GsonBuilder */
public static void setSingletonInstance(@NonNull Gson gson) {
if (gson == null) {
throw new IllegalArgumentException("Gson must not be null");
}
synchronized (JsonParseUtil.class) {
if (singleton != null) {
throw new IllegalStateException("Singleton instance already exists");
}
singleton = gson;
}
}
/** * Json转Object * <p> * 如:UserInfo * * UserInfo userInfo = JsonParseUtil.parseToObject(dataStr,UserInfo.class); * * @param dataStr String */
public static <T> T parseToObject(String dataStr,Class<T> cls) {
if (TextUtils.isEmpty(dataStr)) {
return null;
}
/*T t = getSingleton().fromJson(dataStr,cls);*/
T t = JSON.parSEObject(dataStr,cls);
return t;
}
/** * Json转Object * <p> * 如:UserInfo * * UserInfo userInfo = JsonParseUtil.parseToObject(dataStr,UserInfo.class); * * 只在 GSON 中适用 * * @param jsonElement JsonElement */
public static <T> T parseToObject(Object jsonElement,Class<T> cls) {
if (jsonElement instanceof String) {
return parseToObject(jsonElement,cls);
}
if (jsonElement instanceof JsonElement && !((JsonElement)jsonElement).isJsonNull()) {
T t = getSingleton().fromJson((JsonElement)jsonElement,cls);
return t;
}
return parseToObject("",cls);
}
/** * Json转泛型Object * <p> * 如:HttpResult<UserInfo> * * HttpResult<UserInfo> tmp * = JsonParseUtil.parseToGenericObject(dataStr,new GenericType<HttpResult<UserInfo>>(){}) */
public static <T> T parseToGenericObject(String dataStr,GenericType<T> genericType) {
if (TextUtils.isEmpty(dataStr)) {
return null;
}
/*T t = getSingleton().fromJson(dataStr,genericType.getType());*/
T t = JSON.parSEObject(dataStr,genericType.getType());
return t;
}
/** * Object转Json String * <p> * 如:UserInfo */
public static String parseToJson(Object object) {
/*return (object == null) ? "" : getSingleton().toJson(object);*/
return (object == null) ? "" : JSON.toJSONString(object);
}
/** * Json转单纯的List (dataStr为一个完整Json数组) * <p> * 如:[{"code":1,"name":"小米"},{"code":2,"name":"大米"}] --> List<GoodInfo> */
public static <T> List<T> parseToPureList(String dataStr,Class<T> cls) {
/*if (TextUtils.isEmpty(dataStr)) { return null; } T[] array = getSingleton().fromJson(dataStr,cls); return new ArrayList<>(Arrays.asList(array));*/
List<T> list = JSON.parseArray(dataStr,cls);
return list;
}
/** * Json转指定Class数组 内涵不确定字段名Json数组 * <p> * 如: { "XXX":[{"Id":1352}] } --> List<YYY> */
public static <T> List<T> parseToDynamicList(String dataStr,String fieldName,Class<T> cls) {
String listData = "";
if (!TextUtils.isEmpty(dataStr)) {
try {
JSONObject jsonObj = new JSONObject(dataStr);
listData = jsonObj.optString(fieldName);
} catch (JSONException exp) {
}
}
return parseToPureList(listData,cls);
}
/** * Json转指定Class 内涵不确定字段名Json对象 * <p> * 如: { "XXX":{"Id":1352} } --> YYY */
public static <T> T parseToDynamicObject(String dataStr,Class<T> cls) {
String objectData = "";
if (!TextUtils.isEmpty(dataStr)) {
try {
JSONObject jsonObj = new JSONObject(dataStr);
objectData = jsonObj.optString(fieldName);
} catch (JSONException exp) {
}
}
return parseToObject(objectData,cls);
}
}
GenericType,上面提到的统一获取泛型具体类型。 /** * GenericType.java */
public class GenericType<T> {
private final Type type;
protected GenericType(){
Type superClass = getClass().getGenericSuperclass();
type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
}
最后附上一个JsonParseUtil对HttpResult的使用姿势,其他简单的就自己领悟了。
HttpResult<UserInfo> httpResult = JsonParseUtil.parseToGenericObject(response,new GenericType<HttpResult<UserInfo>>(){});
HttpResult httpResult = JsonParseUtil.parseToObject(response,HttpResult.class);
if (httpResult != null && httpResult.getData() != null) {
UserInfo userInfo;
//注意这里两个JsonParseUtil.parseToObject(...)方法是不一样的
//FastJson 调用方式
userInfo = JsonParseUtil.parseToObject(httpResult.getData().toString(),UserInfo.class);
//Gson 调用方式
userInfo = JsonParseUtil.parseToObject(httpResult.getData(),UserInfo.class);
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |