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

來源:互聯網
上載者:User

標籤:

代碼在最後

我個人是不太喜歡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,否則它就是基礎資料型別 (Elementary Data Type),是不可能進入該方法的

2.遍曆執行個體的所有屬性並且從JSONObject去取值

3.通過反射的getType方法獲得對應的類,這裡需要區分基本類型與封裝類型

4.如果是List那麼就走array的方法,如果是JSONObject那麼繼續遞迴自己

5.JSONArray直接解析,如果拿出的 String包含className,那麼它是pojo繼續遞迴JSONObject,否則結束,直接add成ArrayList<Object>

6.如果是基礎資料型別 (Elementary Data Type),那麼直接通過反射調用set 賦值

7.如果是List,那麼在遞迴後JSONArray會返回一個List<Object> 直接set

 

到這裡,基本搞定了,然後近百號欄位也能夠自動封裝了,反正省去了我一大把的去get值的時間。

 

點擊擷取範例程式碼

 

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.