(原)编写JAVA工具之json自动封装成pojo

代码在最后

我个人是不太喜欢http和json,可能是游戏做的多了的原因的,对通信协议和通信方式特敏感,因此即使是做应用我也会选择rpc而非http,但是有时候因为各种原因,还是不的不处理标准的http+json的东西。

这一次也确实需要处理一大串json,就是将一大堆的json转换成标准的java pojo。也许小json串我们可以直接用JSONObject去提值就行了,但是如果json是这样:

 

一个拥有近百个不一样的字段的pojo,如果我们需要单独的去取值估计会疯掉,这还不是主要的,更蛋疼的是pojo本身的属性又是array或者其他pojo,这样依次嵌套,估计我已经疯了。另外还有一个问题就是如果字段名称一修改,就的手动去修改get的那个名称,完全是苦力活。

(ps:上面那个图,是nutch+es返回的值,我自己弄了一个搜索引擎玩,所有返回有大坨的数据,但是我实际处理的不是这个数据,这里只是用它举例,自己搞的搜索引擎在:

http://search.bucry.com/ 纯粹是为了好玩而已)

但是我又不得不面对这个问题,就是把这一大串json弄成pojo,于是我自然想到偷懒,想用一个东西自动的将它封装成pojo,自动识别pojo的字段,自动从json中去取,并且自动调用set赋值,那么即使后面修改了字段名称,又怎样?无所谓,它本身就是反射,于是开始动手做,我需要解决的问题如下:

 

1.遍历pojo的属性,拿到它的属性的这个变量的名称

2.根据属性的名称,从JSONObject里面去get值

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值的时间。

 

点击获取示例代码

 

posted @ 2015-07-05 23:10  衍悔  阅读(3606)  评论(3编辑  收藏  举报