(原)編寫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值的時間。

 

點擊獲取示例代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM