背景:业务需要,不可以用第三方json解析的开源项目,然后项目中又有很多接口都需要用到把字符串解析为对象的功能。
于是只能自己用原生的写一个了。吐槽(业务需要)。。。
致谢:
Android框架之路——Json解析一篇就够(原生技术+Gson+FastJson)
getDeclaredFields()-Reflection反射-获取包括父类在内的所有字段
正文:
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class JsonUtils {
private static final String TAG = JsonUtils.class.getSimpleName();
/**
* 解析json字符串到实例对象
*
* @param clazz 和JSON对应的类的Class,必须拥有setXxx()函数,其中xxx为属性
* @param json 被解析的JSON字符串
* @return 返回传入的Object对象实例
*/
public static <T> T parseJson2Object(String json, Class<T> clazz) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
return null;
}
return parseJson2Object(clazz, jsonObject);
}
/**
* 解析JSONObject对象到具体类,递归算法
*
* @param clazz 和JSON对应的类的Class,必须拥有setXxx()函数,其中xxx为属性
* @param jsonObject 被解析的JSON对象
* @return 返回传入的Object对象实例
*/
private static <T> T parseJson2Object(Class<T> clazz, JSONObject jsonObject) {
T obj = null;
try {
//获取clazz的实例
obj = clazz.newInstance();
Class tempClass = clazz;
List<Field> fieldList = new ArrayList<>();
while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
}
// Collections.reverse(fieldList);
// 遍历每个属性,如果为基本类型和String则直接赋值,如果为List则得到每个Item添加后再赋值,如果是其它类则得到类的实例后赋值
for (Field field : fieldList) {
try {
// 设置属性可操作
field.setAccessible(true);
// if (field.getName().equals("serialVersionUID")) {
// continue;
// }
FSLogcat.e(TAG, " GenericType = " + field.getGenericType().toString());
// 获取字段类型
Class<?> typeClazz = field.getType();
// 是否基础变量 Boolean,Character,Byte,Short,Integer,Long,Float,Double,Void
if (typeClazz.isPrimitive()) {
if (field.getGenericType().toString().equals("float")) {
Object opt = jsonObject.opt(field.getName());
if (opt instanceof Double) {
setProperty(obj, field, ((Double) opt).floatValue());
} else {
setProperty(obj, field, jsonObject.opt(field.getName()));
}
} else {
setProperty(obj, field, jsonObject.opt(field.getName()));
}
} else {
// 得到类型实例
Object typeObj;
if (typeClazz.isInterface() && typeClazz.getSimpleName().contains("List")) {//Field如果声明为List<T>接口,由于接口的Class对象不能newInstance(),此时需要转化为ArrayList
typeObj = ArrayList.class.newInstance();
} else {
typeObj = typeClazz.newInstance();
}
if (field.getName().equals("testMap")) {
Log.e(TAG, " pause");
}
if (typeObj instanceof Map) {// 是否为Map
try {
// 得到Map的JSONObject
JSONObject object = jsonObject.getJSONObject(field.getName());
// 得到类型的结构,如:java.util.HashMap<com.xxx.xxx>
Type type = field.getGenericType();
ParameterizedType pt = (ParameterizedType) type;
// 获得Map元素键类型
// Class<?> keyClass = (Class<?>) pt.getActualTypeArguments()[0];
// 获得Map元素值类型
Class<?> valueClass = (Class<?>) pt.getActualTypeArguments()[1];
JSONArray names = object.names();
for (int i = 0; i < names.length(); i++) {
try {
// 默认按map值为String进行解析
String key = names.opt(i).toString();
Object value = parseJson2Object(valueClass, object.getJSONObject(key));
((Map<String, Object>) typeObj).put(key, value);
} catch (Exception e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
}
setProperty(obj, field, typeObj);
} catch (Exception e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
} else if (typeObj instanceof List) {// 是否为List
// 得到类型的结构,如:java.util.ArrayList<com.xxx.xxx>
Type type = field.getGenericType();
ParameterizedType pt = (ParameterizedType) type;
// 获得List元素类型
Class<?> dataClass = (Class<?>) pt.getActualTypeArguments()[0];
// 得到List的JSONArray数组
JSONArray jArray = jsonObject.getJSONArray(field.getName());
// 将每个元素的实例类加入到类型的实例中
for (int i = 0; i < jArray.length(); i++) {
//对于数组,递归调用解析子元素
try {
((List<Object>) typeObj).add(parseJson2Object(dataClass, jsonObject.getJSONArray(field.getName()).getJSONObject(i)));
} catch (JSONException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
}
setProperty(obj, field, typeObj);
} else if (typeObj instanceof String) {// 是否为String
setProperty(obj, field, jsonObject.opt(field.getName()));
} else {//是否为其它对象
//递归解析对象
try {
setProperty(obj, field, parseJson2Object(typeClazz, jsonObject.getJSONObject(field.getName())));
} catch (JSONException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
}
}
} catch (JSONException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
} catch (IllegalAccessException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
} catch (InstantiationException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
}
} catch (IllegalAccessException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
} catch (InstantiationException e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
return obj;
}
/**
* 给实例对象的成员变量赋值
*
* @param obj 实例对象
* @param field 要被赋值的成员变量
* @param valueObj 要被赋值的成员变量的值
*/
private static void setProperty(Object obj, Field field, Object valueObj) {
if (valueObj == null) {
return;
}
// // 兼容类继承情况的判断
Class<?> tempClass = obj.getClass();
while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
try {
Method method = tempClass.getDeclaredMethod("set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1), field.getType());
//设置set方法可访问
method.setAccessible(true);
//调用set方法为实例对象的成员变量赋值
method.invoke(obj, valueObj);
break; // 退出循环
} catch (NoSuchMethodException e) {
FSLogcat.e(TAG, "method [set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1) + "] not found");
tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
} catch (IllegalArgumentException e) {
FSLogcat.e(TAG, "method [set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1) + "] illegal argument:" + valueObj + "," + e.getMessage());
break; // 退出循环
} catch (IllegalAccessException e) {
FSLogcat.e(TAG, "IllegalAccessException:" + e.getMessage());
break; // 退出循环
} catch (InvocationTargetException e) {
FSLogcat.e(TAG, "IllegalAccessException:" + e.getMessage());
break; // 退出循环
} catch (Exception e) {
FSLogcat.e(TAG, "Exception:" + e.getMessage());
break; // 退出循环
}
}
// 未兼容类继承后对父类私有方法的获取
// try {
// Class<?> clazz = obj.getClass();
// //获取类的setXxx方法,xxx为属性
// // getMethods(),该方法是获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
// Method method = clazz.getMethod("set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1), field.getType());
// // getDeclaredMethods(),该方法是获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。
Method method = clazz.getDeclaredMethod("set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1), field.getType());
// //设置set方法可访问
// method.setAccessible(true);
// //调用set方法为实例对象的成员变量赋值
// method.invoke(obj, valueObj);
// } catch (NoSuchMethodException e) {
// FSLogcat.e(TAG, "method [set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1) + "] not found");
// } catch (IllegalArgumentException e) {
// FSLogcat.e(TAG, "method [set" + field.getName().substring(0, 1).toUpperCase(Locale.getDefault()) + field.getName().substring(1) + "] illegal argument:" + valueObj + "," + e.getMessage());
// } catch (IllegalAccessException e) {
// FSLogcat.e(TAG, "IllegalAccessException:" + e.getMessage());
// } catch (InvocationTargetException e) {
// FSLogcat.e(TAG, "IllegalAccessException:" + e.getMessage());
// }
}
/**
* 可以解析自定义的对象、map、List、数组、基本数据类型、String
*
* @param value
* @return
*/
public static String object2JsonString(Object value) {
if (value == null) {
return "null";
}
if (value instanceof Boolean) {
return value.toString();
}
if (value instanceof String) {
return "\"" + escape((String) value) + "\"";
}
if (value instanceof Double) {
if (((Double) value).isInfinite() || ((Double) value).isNaN()) {
// return "null";
return "0";
} else {
return value.toString();
}
}
if (value instanceof Float) {
if (((Float) value).isInfinite() || ((Float) value).isNaN()) {
// return "null";
return "0";
} else {
return value.toString();
}
}
if (value instanceof Number) {
return value.toString();
}
if (value instanceof Map) {
return map2Json((Map) value);
}
if (value instanceof Collection) {
return coll2Json((Collection) value);
}
if (value.getClass().isArray()) {
return array2Json(value);
}
return customObject2Json(value);
}
private static String array2Json(Object array) {
if (null == array) {
return "null";
}
StringBuffer sb = new StringBuffer();
sb.append('[');
// 此处减1是为了下面的 逗号 追加
int len = Array.getLength(array) - 1;
if (len > -1) {
int i;
for (i = 0; i < len; i++) {
sb.append(object2JsonString(Array.get(array, i))).append(",");
}
sb.append(object2JsonString(Array.get(array, i)));
}
sb.append(']');
return sb.toString();
}
private static String coll2Json(Collection coll) {
if (null == coll) {
return "null";
}
StringBuffer sb = new StringBuffer();
sb.append('[');
for (Iterator it = coll.iterator(); it.hasNext(); ) {
sb.append(object2JsonString(it.next()));
if (it.hasNext()) {
sb.append(",");
}
}
sb.append(']');
return sb.toString();
}
private static String customObject2Json(Object obj) {
Class tempClass = obj.getClass();
List<Field> fieldList = new ArrayList<>();
while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {//当父类为null的时候说明到达了最上层的父类(Object类).
fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
}
Map map = new HashMap();
for (Field f : fieldList) {
if (Modifier.isStatic(f.getModifiers())) {
continue;
}
String name = f.getName();
f.setAccessible(true);
Object value = null;
try {
value = f.get(obj);
} catch (IllegalAccessException e) {
value = null;
FSLogcat.e(TAG, "Exception:" + e.getMessage());
}
map.put(name, value);
}
tempClass = null;
fieldList = null;
return map2Json(map);
// Class type = obj.getClass();
// Field[] fields = type.getDeclaredFields();
// Map map = new HashMap();
// for (Field f : fields) {
// if (Modifier.isStatic(f.getModifiers())) {
// continue;
// }
// String name = f.getName();
// f.setAccessible(true);
// Object value = null;
// try {
// value = f.get(obj);
// } catch (IllegalAccessException e) {
// value = null;
// FSLogcat.e(TAG, "Exception:" + e.getMessage());
// }
// map.put(name, value);
// }
// type = null;
// fields = null;
// return map2Json(map);
}
private static String map2Json(Map map) {
if (null == map) {
return "null";
}
StringBuffer sb = new StringBuffer();
sb.append('{');
for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
if (null == key) {
continue;
}
sb.append('\"');
escape(key, sb);
sb.append('\"').append(':').append(object2JsonString(entry.getValue()));
if (it.hasNext()) {
sb.append(",");
}
}
sb.append('}');
return sb.toString();
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
*
* @param s
* @return
*/
private static String escape(String s) {
if (s == null) {
return null;
}
StringBuffer sb = new StringBuffer();
escape(s, sb);
return sb.toString();
}
private static void escape(String s, StringBuffer sb) {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
// case '/':
// sb.append("\\/");
// break;
case '/':
sb.append("/");
break;
default:
if ((ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F') || (ch >= '\u2000' && ch <= '\u20FF')) {
String ss = Integer.toHexString(ch);
sb.append("\\u");
for (int k = 0; k < 4 - ss.length(); k++) {
sb.append('0');
}
sb.append(ss.toUpperCase());
} else {
sb.append(ch);
}
}
}
}
}
不足:目前在Map<K,V>结构的数据解析时,只支持Map<K,V>的key为String类型的数据。(PS:Map<K,V>其实是可以使用对象类型做Key的。)
很尴尬,因为原生的new JSONObject(json);时如果json字符串里边的Map<K,V>的key是对象会直接报异常。。。
目前没找到好的方法解决,但是也够用了,如果有找到办法的麻烦知会我一声,以共同进步!非常感谢!!!