通過GSON解析複雜json資料(二)
阿新 • • 發佈:2018-12-26
這裡我們依舊用上文中的 json 字串 , 由於轉換為 map 依舊需要 javaBean , 所有我們的實體物件也不發生改變
這裡我們需要活用 java 反射和型別對比實現需求
先看程式碼
package com.jacx.test.test01.jsonutil;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author 劉合炎
* @description json物件轉java物件
* 此方法使用方法較為駁雜,請結合例子參考 -- JSONTest
*/
public class TestJsonUtil {
/**
* 獲得物件的屬性和集合中的屬性
* @param clazz
* @return
*/
private static List<Field> findFiledsAttr(Class clazz){
Field[] fields = null;
List fieldList = new ArrayList();
while(true){
if(clazz == null){
break ;
}
fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fieldList.add(fields[i]);
System.out.println("fields:" +fields[i]);
Class fieldType = fields[i].getType();
//判斷是否為基本型別
if(fieldType.isPrimitive() || fieldType.toString().equals("class java.lang.String")){
continue;
}else{
//是使用者想要的型別?
//if(fieldType.isAssignableFrom(List.class)){
Type type = fields[i].getGenericType();
if(type == null){
continue;
}
if(type instanceof ParameterizedType){//如果是泛型引數的型別
ParameterizedType pt = (ParameterizedType) type;
Class genericClass = (Class)pt.getActualTypeArguments()[0];//得到泛型的class物件
//System.out.println("genericClass:"+genericClass);
//遞迴直到獲得所有屬性
findFiledsAttr(genericClass);
}
//}
}
}
clazz = clazz.getSuperclass();
}
return fieldList;
}
public static void main(String[] args) {
List<Field> fields= findFiledsAttr(TestGsonUnSer.class);
for (int i = 0; i < fields.size(); i++) {
System.out.println(fields.get(i));
}
}
/**
* 轉換操作
* @param obj 基本物件
* @param obj2 物件中的物件
* @param ignores 是否摒棄
* @return
*/
public static Map convertBean2Map(Object obj,String[] ignores){
Map map = new LinkedHashMap();
Class clazz = obj.getClass();
List<Field> fields = findFiledsAttr(clazz);
Field field = null;
List taskList = null;
for (int i = 0; i < fields.size(); i++) {
field = fields.get(i);
boolean flag = false;
if(ignores != null && ignores.length > 0){
flag = isExistOfIgnores(field.getName(), ignores);
}
if(!flag){
Object value = getProperty(obj, field.getName());
if(null != value/* && !StringUtils.EMPTY.equals(value.toString())*/){
//判斷是否為基本型別
if(field.getType().isPrimitive() || field.getType().toString().equals("class java.lang.String")){
//基本型別直接設值即可
map.put(field.getName(), getProperty(obj, field.getName()));
}else if(field.getType().isAssignableFrom(List.class)){
PropertyDescriptor pd = getPropertyDescriptor(obj.getClass(), field.getName());
Method getMethod = pd.getReadMethod();
Object objValue = null;
try {
objValue = getMethod.invoke(obj, new Object[]{});
System.out.println("finalValue:"+objValue);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(objValue instanceof List<?>){
System.out.println("===========================");
taskList = (List)objValue;
}
System.out.println("pd.getReadMethod():"+pd.getReadMethod());
/*//獲取class型別中的propertyName屬性
PropertyDescriptor pd = getPropertyDescriptor(obj.getClass(), field.getName());
//從屬性描述器中獲取get方法
Method getMethod = pd.getReadMethod();
System.out.println("field.getClass():"+getMethod);*/
//遍歷巢狀物件中的元素
//System.out.println("obj2:"+obj2);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class genericClass = (Class)pt.getActualTypeArguments()[0];//得到泛型的class物件
/*if (obj2 instanceof List<?>){
taskList = (List)obj2;
}*/
List<LinkedHashMap<String, Object>> sonMap = new ArrayList<LinkedHashMap<String, Object>>();
for (int j = 0; j < taskList.size(); j++) {
List<Field> sonFields = findFiledsAttr(taskList.get(j).getClass());
LinkedHashMap<String,Object> son2Map = new LinkedHashMap<String, Object>();
for (int k = 0; k < sonFields.size(); k++) {
System.out.println("sonFields.get(k).getName():"+sonFields.get(k).getName());
if(sonFields.get(k).getType().isPrimitive() || sonFields.get(k).getType().toString().equals("class java.lang.String")){
son2Map.put(sonFields.get(k).getName(), getProperty(taskList.get(j), sonFields.get(k).getName()));
System.out.println("子物件中的資料:"+son2Map);
}else{
//遞迴至基本型別或String
convertBean2Map(getProperty(taskList.get(j), sonFields.get(k).getName()));
}
}
sonMap.add(son2Map);
map.put(field.getName(), sonMap);
}
}else{
PropertyDescriptor pd = getPropertyDescriptor(obj.getClass(), field.getName());
Method getMethod = pd.getReadMethod();
Object objValue2 = null;
try {
objValue2 = getMethod.invoke(obj, new Object[]{});
System.out.println("finalValue:"+objValue2);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
List<Field> sonFields = findFiledsAttr(objValue2.getClass());
Map<String,Object> sonMap = new LinkedHashMap<String, Object>();
for (int j = 0; j < sonFields.size(); j++) {
if(sonFields.get(j).getType().isPrimitive() || sonFields.get(j).getType().toString().equals("class java.lang.String")){
System.out.println("sonFields.get(j).getName():"+sonFields.get(j).getName());
sonMap.put(sonFields.get(j).getName(), getProperty(objValue2, sonFields.get(j).getName()));
System.out.println("子物件中的資料:"+sonMap);
}else{
//遞迴至基本型別或String
convertBean2Map(getProperty(objValue2, sonFields.get(j).getName()));
}
}
map.put(field.getName(), sonMap);
}
}
}
}
return map;
}
/**
* 過載
* @param obj
* @param obj2
* @return
*/
public static Map convertBean2Map(Object obj){
return convertBean2Map(obj,null);
}
public static Map convertBean2MapForIngoreserialVersionUID(Object obj) {
return convertBean2Map(obj, new String[] { "serialVersionUID" });
}
private static boolean isExistOfIgnores(String fieldName,String[] ignores){
boolean flag = false;
for(String str : ignores){
if(str.equals(fieldName)){
flag = true;
break;
}
}
return flag;
}
/**
* 通過set方法設值
* @param obj
* @param propertyName
* @param value
*/
@SuppressWarnings("unchecked")
private static void setProperty(Object obj, String propertyName,Object value) {
Class clazz = obj.getClass();// 獲取物件的型別
PropertyDescriptor pd = getPropertyDescriptor(clazz, propertyName);// 獲取 clazz型別中的propertyName的屬性描述器
Method setMethod = pd.getWriteMethod();// 從屬性描述器中獲取 set 方法
try {
setMethod.invoke(obj, new Object[] {value});// 呼叫 set 方法將傳入的value值儲存屬性中去
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通過get方法獲取物件屬性值對應的值
* @param obj
* @param propertyName
* @return
*/
private static Object getProperty(Object obj,String propertyName){
Class clazz = obj.getClass();
//獲取class型別中的propertyName屬性
PropertyDescriptor pd = getPropertyDescriptor(clazz, propertyName);
//從屬性描述器中獲取get方法
Method getMethod = pd.getReadMethod();
Object value = null;
try {
//呼叫value方法將傳入的value值儲存至屬性中
value = getMethod.invoke(obj, new Object[]{});
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return value;
}
/**
* get和set方法取值
* @param clazz
* @param propertyName
* @return
*/
private static PropertyDescriptor getPropertyDescriptor(Class clazz,String propertyName){
StringBuffer sb = new StringBuffer();//儲存方法名稱
Method setMethod = null;
Method getMethod = null;
PropertyDescriptor pd = null;
try {
//根據欄位名獲取欄位
Field f = clazz.getDeclaredField(propertyName);
if(f != null){
String methodEnd = propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
//構建set方法
sb.append("set" + methodEnd);
setMethod = clazz.getDeclaredMethod(sb.toString(), new Class[]{f.getType()});
//構建get方法
sb.delete(0, sb.length());//清空
sb.append("get"+methodEnd);
getMethod = clazz.getDeclaredMethod(sb.toString(), new Class[]{});
System.out.println("getMethod:"+getMethod);
pd = new PropertyDescriptor(propertyName, getMethod,setMethod);
}
} catch (NoSuchFieldException e) {
System.out.println("實體物件中沒有此屬性==="+e.getMessage());
} catch (SecurityException e) {
System.out.println("此方法為私有的或訪問許可權不足==="+e.getMessage());
} catch (NoSuchMethodException e) {
System.out.println("實體物件中的屬性必須有get/set方法==="+e.getMessage());
} catch (IntrospectionException e) {
e.printStackTrace();
}
return pd;
}
}
可以看到 , 在此工具類中通過反射機制拿到所有的屬性和屬性型別 , 將基本資料型別+String和物件型別分開做不同操作 , 通過方法反射拼接get和set方法取值/設值
這裡重中之重依舊是分析 json 應該轉換為何種型別
public static void main(String[] args) {
String str = "[{\"users\":[{\"name\":\"系統001\",\"code\":\"sys01\"},{\"name\":\"系統003\",\"code\":\"sys03\"}],\"travel_theme\":\"測試002\",\"travel_start_time\":\"2017-08-08 10:07\",\"travel_end_time\":\"2017-08-22 10:07\",\"process_start_time\":\"2017-08-07 10:09:06\",\"process_end_time\":\"2017-08-07 10:28:46\"},{\"users\":[{\"name\":\"系統002\",\"code\":\"sys002\"}],\"travel_theme\":\"測試004\",\"travel_start_time\":\"2017-08-07 10:11\",\"travel_end_time\":\"2017-08-08 10:11\",\"process_start_time\":\"2017-08-07 10:12:34\",\"process_end_time\":\"2017-08-07 10:28:51\"}]";
Gson gson = new Gson();
List<TestGsonUnSer> list = gson.fromJson(str, new TypeToken<List<TestGsonUnSer>>(){}.getType());
System.out.println("list:"+list);
System.out.println(list.get(0).getUsers().get(0).getName());
List<Map<String, List<Map<String, Object>>>> maps = new ArrayList<>();
LinkedHashMap<String,List<Map<String, Object>>> sonMap = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.get(i).getUsers().size(); j++) {
sonMap = (LinkedHashMap<String, List<Map<String, Object>>>)
//第一個引數為最外層 javaBean 類型別,第二個為 List,傳入引數的同時將資料全部帶入
TestJsonUtil.convertBean2Map(list.get(i), list.get(i).getUsers());
System.out.println("list.get(i).getUsers().get(0):"+list.get(i).getUsers().get(j));
System.out.println("sonMap:"+sonMap);
//maps.add(sonMap);
}
maps.add(sonMap);
}
System.out.println("maps:"+maps);
}
最後 maps 輸出
maps:[{users=[{name=系統001, code=sys01}, {name=系統003, code=sys03}], travel_theme=測試002, travel_start_time=2017-08-08 10:07, travel_end_time=2017-08-22 10:07, process_start_time=2017-08-07 10:09:06, process_end_time=2017-08-07 10:28:46}, {users=[{name=系統002, code=sys002}], travel_theme=測試004, travel_start_time=2017-08-07 10:11, travel_end_time=2017-08-08 10:11, process_start_time=2017-08-07 10:12:34, process_end_time=2017-08-07 10:28:51}]
和我們想要的結果一致