代码在最后java
我我的是不太喜欢http和json,多是游戏作的多了的缘由的,对通讯协议和通讯方式特敏感,所以即便是作应用我也会选择rpc而非http,可是有时候由于各类缘由,仍是不的不处理标准的http+json的东西。git
这一次也确实须要处理一大串json,就是将一大堆的json转换成标准的java pojo。也许小json串咱们能够直接用JSONObject去提值就好了,可是若是json是这样:github
一个拥有近百个不同的字段的pojo,若是咱们须要单独的去取值估计会疯掉,这还不是主要的,更蛋疼的是pojo自己的属性又是array或者其余pojo,这样依次嵌套,估计我已经疯了。另外还有一个问题就是若是字段名称一修改,就的手动去修改get的那个名称,彻底是苦力活。json
(ps:上面那个图,是nutch+es返回的值,我本身弄了一个搜索引擎玩,全部返回有大坨的数据,可是我实际处理的不是这个数据,这里只是用它举例,本身搞的搜索引擎在:服务器
http://search.bucry.com/ 纯粹是为了好玩而已)搜索引擎
可是我又不得不面对这个问题,就是把这一大串json弄成pojo,因而我天然想到偷懒,想用一个东西自动的将它封装成pojo,自动识别pojo的字段,自动从json中去取,而且自动调用set赋值,那么即便后面修改了字段名称,又怎样?无所谓,它自己就是反射,因而开始动手作,我须要解决的问题以下:spa
1.遍历pojo的属性,拿到它的属性的这个变量的名称code
2.根据属性的名称,从JSONObject里面去get值blog
3.在JSONObject里面get值的时候是须要知道变量的类型的,若是它是一个pojo,那么继续递归调用走 1递归
4.在JSONObject里面get值的时候若是是一个List活着Array那么使用JSONArray,而后经过String取出值,再判断String,递归走2
5.反射调用set方法赋值
6.包装成功
要解决上面的问题,首先我想到的是反射,可是反射在将其反射的时候必须知道类全路径,因而我这个东西有其局限性:
pojo类必须有这个字段:
private String className = RowResponse.class.getName();
也就是服务器在tojson的时候把这个字段传给客户端,客户端在原封不动的传送给服务器,那么就可以成功的经过递归自动封装全部的pojo,有人会说这样多一个字段数据量会增大,会使通讯变慢的,这里我想说的是,json已经大到我须要这样去处理pojo的程度了,还管个卵的速度,这一大坨的东西注定它快不了。
首先咱们必须有两个方法,一个是处理JSONObject,另外一个是处理JSONArray 的,而后它们之间会相互交叉调用,它们自己会相互递归调用:
public Object translateFromJson(JSONObject jsonObject) throws Exception { JSONType jsonType = JSONType.JSONOBJECT; Class<?> baseClass = Class.forName(jsonObject.getString("className")); Object object = baseClass.newInstance(); Field[] fields = baseClass.getDeclaredFields(); for (Field filed : fields) { Class<?> filedType = filed.getType(); Object filedValue = null; if ("serialVersionUID".equals(filed.getName())) { continue; } if (filedType.getCanonicalName().contains("int") || filedType.getCanonicalName().contains("Integer")) { filedValue = jsonObject.getInt(filed.getName()); } else if (filedType.getCanonicalName().contains("String")) { filedValue = jsonObject.getString(filed.getName()); } else if (filedType.getCanonicalName().contains("List")) { jsonType = JSONType.JSONARRAY; filedValue = jsonObject.getJSONArray(filed.getName()); } else if (filedType.getCanonicalName().contains("Long") || filedType.getCanonicalName().contains("long")) { filedValue = jsonObject.getLong(filed.getName()); } else if (filedType.getCanonicalName().contains("Double") || filedType.getCanonicalName().contains("double")) { filedValue = jsonObject.getDouble(filed.getName()); } else if (filedType.getCanonicalName().contains("Boolean") || filedType.getCanonicalName().contains("boolean")) { filedValue = jsonObject.getBoolean(filed.getName()); } else { jsonType = JSONType.JSONOBJECT; filedValue = jsonObject.getJSONObject(filed.getName()); } if (filedValue == null || filedValue.toString().length() == 0) { continue; } if (!filedValue.toString().contains("[{") && !filedValue.toString().contains("]}") && !filedValue.toString().contains("className")) { String firstMethodNameChar = filed.getName().substring(0, 1); String methodName = "set" + firstMethodNameChar.toUpperCase() + filed.getName().substring(1, filed.getName().length()); Method method = baseClass.getMethod(methodName, filed.getType()); method.invoke(object, filedValue); } else if (filedValue.toString().contains("className")) { Object subClassObject = null; switch (jsonType) { case JSONARRAY: subClassObject = translateFromJson((JSONArray)filedValue); break; case JSONOBJECT: subClassObject = translateFromJson((JSONObject)filedValue); break; } String firstMethodNameChar = filed.getName().substring(0, 1); String methodName = "set" + firstMethodNameChar.toUpperCase() + filed.getName().substring(1, filed.getName().length()); Method method = baseClass.getMethod(methodName, filed.getType()); method.invoke(object, subClassObject); } else { Object subClassObject = null; switch (jsonType) { case JSONARRAY: subClassObject = translateFromJson((JSONArray)filedValue); break; case JSONOBJECT: subClassObject = translateFromJson((JSONObject)filedValue); break; } String firstMethodNameChar = filed.getName().substring(0, 1); String methodName = "set" + firstMethodNameChar.toUpperCase() + filed.getName().substring(1, filed.getName().length()); Method method = baseClass.getMethod(methodName, filed.getType()); method.invoke(object, subClassObject); } } return object; }
public Object translateFromJson(JSONArray jsonObject) throws Exception { List<Object> outputStringList = new LinkedList<Object>(); for(int i=0; i<jsonObject.length(); i++){ String filedValue = jsonObject.get(i).toString(); if (filedValue.contains("className")) { JSONObject jsonObject1 = new JSONObject(filedValue); outputStringList.add(translateFromJson(jsonObject1)); } else { outputStringList.add(filedValue); } } return outputStringList; }
处理过程以下:
1.根据className反射出了这个类的一个实例,因为是进入JSONObjct那么它必定是pojo,不然它就是基本数据类型,是不可能进入该方法的
2.遍历实例的全部属性而且从JSONObject去取值
3.经过反射的getType方法得到对应的类,这里须要区分基本类型与包装类型
4.若是是List那么就走array的方法,若是是JSONObject那么继续递归本身
5.JSONArray直接解析,若是拿出的 String包含className,那么它是pojo继续递归JSONObject,不然结束,直接add成ArrayList<Object>
6.若是是基本数据类型,那么直接经过反射调用set 赋值
7.若是是List,那么在递归后JSONArray会返回一个List<Object> 直接set
到这里,基本搞定了,而后近百号字段也可以自动封装了,反正省去了我一大把的去get值的时间。