(原)編寫JAVA工具之json自動封裝成pojo

代碼在最後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值的時間。

 

點擊獲取示例代碼

相關文章
相關標籤/搜索