1. 程式人生 > >自動根據json字串生成javabean類

自動根據json字串生成javabean類

你還在為文件裡鋪天蓋地滴變數, 結構複雜的json而煩惱嗎~
寫錯了一個型別,然後各種崩潰
寫錯了一個變數名無法解析
...

程式碼工具來啦~
自動生成javabean類,只要一鍵~

懶是一種程式設計師的必備美德,程式設計師都應該學會躲懶
擼的過程中一切重複枯燥無技術含量的工作都是可恥的,
此係列的程式碼工具就致力於此,替你完成這些無聊的工作,讓你有更多的精力時間研究新姿勢

----------------------------------------------------------------------

使用方法
先將程式碼工具匯入Eclipse, 該專案為Java Project,注意不是Android Project

1.將json字串資料複製到專案中的jsonString.txt檔案中
(json資料可以從文件中的json資料示例裡,或先執行一遍介面呼叫程式碼打印出來json字串獲取到)



2.執行程式碼工具中的JsonUtils類,其中的main函式中會執行json解析主方法



3.開啟JsonBean.java檔案,重新整理,複製其中自動生成好的javabean類直接使用


補充
如果需要public修飾變數,可以ctrl+F進行全部替換
如果需要生成getter and setter方法,可以右鍵Source->Generate Getter and Setter進行設定



工具程式碼已開源,也可以根據需求自行修改

Github地址

https://github.com/boredream/CodeUtils
歡迎star 和 folk,除了這裡的json解析工具還有其他功能
後續還會一直提供不同新功能,大家有需求也可以提出,特別常用的都會找時間儘量新增

回覆可見是希望帖子頂上去更多人能看到,希望理解

好了,工具使用到此結束,後面介紹下程式碼原理等

----------------------------------------------------------------------

原理
專案為一個Java Project
利用Gson工具將字串樹結構解析出來,然後利用File IO流將bean結構根據需求生成程式碼再寫入到檔案中

可見專案中原始碼,良心註釋,幾乎2行程式碼1行註釋
這裡也貼出下核心類JsonUtils的程式碼

  1. package utils;
  2. import java.io.File;
  3. import java.util.ArrayList;
  4. import java.util.Iterator;
  5. import java.util.List;
  6. import java.util.Map.Entry;
  7. import com.google.gson.JsonArray;
  8. import com.google.gson.JsonElement;
  9. import com.google.gson.JsonObject;
  10. import com.google.gson.JsonParser;
  11. import com.google.gson.JsonPrimitive;
  12. import entity.ArrayType;
  13. import entity.Json2JavaElement;
  14. public class JsonUtils {
  15.      public static void main(String[] args) {
  16.           parseJson2Java();
  17.      }
  18.      /**
  19.      * 將json字串轉換為對應的javabean
  20.      *
  21.      * <p>
  22.      * 用法:<br>
  23.      * 將json字串拷貝至本專案中/Json/JsonString.txt 檔案中去,然後呼叫該方法,<br>
  24.      * 就會在本專案中/Json/JsonBean.java中生成一個對應的JavaBean類<br><br>
  25.      * 注意:<br>
  26.      * 如果json字串中有null或者空集合[]這種無法判斷型別的,會統一使用Object型別
  27.      */
  28.      public static void parseJson2Java() {
  29.           /// 讀取json字串
  30.           String string = FileUtils.readToString(new File("Json\\JsonString.txt"), "UTF-8");
  31.           // 解析獲取整個json結構集合
  32.           JsonParser parser = new JsonParser();
  33.           JsonElement element = parser.parse(string);
  34.           JsonObject jo = element.getAsJsonObject();
  35.           List<Json2JavaElement> jsonBeanTree = getJsonBeanTree(jo);
  36.           // 利用獲取到的json結構集合,建立對應的javabean檔案內容
  37.           String javaBeanStr = createJavaBean(jsonBeanTree);
  38.           // 將生成的內容寫入到檔案中去
  39.           FileUtils.writeString2File(javaBeanStr, new File("Json\\JsonBean.java"));
  40.      }
  41.      /**
  42.      * 根據解析好的資料建立生成對應的javabean類字串
  43.      *
  44.      * @param jsonBeanTree 解析好的資料集合
  45.      * @return 生成的javabean類字串
  46.      */
  47.      private static String createJavaBean(List<Json2JavaElement> jsonBeanTree) {
  48.           StringBuilder sb = new StringBuilder();
  49.           // 是否包含自定義子類
  50.           boolean hasCustomeClass = false;
  51.           List<String> customClassNames = new ArrayList<String>();
  52.           sb.append("public class JsonBeans {\n");
  53.           // 由於在迴圈的時候有移除操作,所以使用迭代器遍歷
  54.           Iterator<Json2JavaElement> iterator = jsonBeanTree.iterator();
  55.           while(iterator.hasNext()) {
  56.                Json2JavaElement j2j = iterator.next();
  57.                // 儲存自定義類名稱至集合中,注意已經包含的不再新增
  58.                if(j2j.getCustomClassName() != null && !customClassNames.contains(j2j.getCustomClassName())) {
  59.                     customClassNames.add(j2j.getCustomClassName());
  60.                }
  61.                if(j2j.getParentJb() != null) {
  62.                     // 如果有parent,則為自定義子類,設定識別符號不做其他操作
  63.                     hasCustomeClass = true;
  64.                } else {
  65.                     // 如果不是自定義子類,則根據型別名和控制元件物件名生成變數申明語句
  66.                     // private TextView tv_name;
  67.                     sb.append("\tprivate ")
  68.                          .append(getTypeName(j2j))
  69.                          .append(" ")
  70.                          .append(j2j.getName())
  71.                          .append(";\n");
  72.                     // 已經使用的資料會移除,則集合中只會剩下自定義子類相關的元素資料,將在後續的迴圈中處理
  73.                     iterator.remove();
  74.                }
  75.           }
  76.           // 設定所有自定義類
  77.           if(hasCustomeClass) {
  78.                for(String customClassName : customClassNames) {
  79.                     // 根據名稱申明子類
  80.                     // /*sub class*/
  81.                     // public class CustomClass {
  82.                     sb.append("\n\t/*sub class*/\n");
  83.                     sb.append("\tpublic class ")
  84.                          .append(customClassName)
  85.                          .append(" {\n");
  86.                     // 迴圈餘下的集合
  87.                     Iterator<Json2JavaElement> customIterator = jsonBeanTree.iterator();
  88.                     while(customIterator.hasNext()) {
  89.                          Json2JavaElement j2j = customIterator.next();
  90.                          // 根據當前資料的parent名稱,首字母轉為大寫生成parent的類名
  91.                          String parentClassName = StringUtils.firstToUpperCase(j2j.getParentJb().getName());
  92.                          // 如果當前資料屬於本次外層迴圈需要處理的子類
  93.                          if(parentClassName.equals(customClassName)) {
  94.                               // 根據型別名和控制元件物件名生成變數申明語句
  95.                               // private TextView tv_name;
  96.                               sb.append("\t\tprivate ")
  97.                                    .append(getTypeName(j2j))
  98.                                    .append(" ")
  99.                                    .append(j2j.getName())
  100.                                    .append(";\n");
  101.                               // 已經使用的資料會移除,減少下一次外層迴圈的遍歷次數
  102.                               customIterator.remove();
  103.                          }
  104.                     }
  105.                     sb.append("\t}\n");
  106.                }
  107.           }
  108.           sb.append("}");
  109.           return sb.toString();
  110.      }
  111.      /**
  112.      *  遞迴遍歷整個json資料結構,儲存至jsonBeans集合中
  113.      * 
  114.      *  @param rootJo 根json物件
  115.      *  @return 解析好的資料集合
  116.      */
  117.      private static List<Json2JavaElement> getJsonBeanTree(JsonObject rootJo) {
  118.           jsonBeans = new ArrayList<Json2JavaElement>();
  119.           recursionJson(rootJo, null);
  120.           return jsonBeans;
  121.      }
  122.      /**
  123.      * 儲存遞迴獲取到資料的集合
  124.      */
  125.      private static List<Json2JavaElement> jsonBeans = new ArrayList<Json2JavaElement>();
  126.      /**
  127.      * 遞迴獲取json資料
  128.      *
  129.      * @param jo 當前遞迴解析的json物件
  130.      * @param parent 已經解析好的上一級資料,無上一級時傳入null
  131.      */
  132.      private static void recursionJson(JsonObject jo, Json2JavaElement parent) {
  133.           // 迴圈整個json物件的鍵值對
  134.           for (Entry<String, JsonElement> entry : jo.entrySet()) {
  135.                // json物件的鍵值對建構為 {"key":value}
  136.                // 其中,值可能是基礎型別,也可能是集合或者物件,先解析為json元素
  137.                String name = entry.getKey();
  138.                JsonElement je = entry.getValue();
  139.                Json2JavaElement j2j = new Json2JavaElement();
  140.                j2j.setName(name);
  141.                if(parent != null) {
  142.                     j2j.setParentJb(parent);
  143.                }
  144.                // 獲取json元素的型別,可能為多種情況,如下
  145.                Class<?> type = getJsonType(je);
  146.                if(type == null) {
  147.                     // 自定義型別
  148.                     // json鍵值的首字母轉為大寫,作為自定義類名
  149.                     j2j.setCustomClassName(StringUtils.firstToUpperCase(name));
  150.                     // ?
  151.                     j2j.setSouceJo(je.getAsJsonObject());
  152.                     jsonBeans.add(j2j);
  153.                     // 自定義類需要繼續遞迴,解析自定義類中的json結構
  154.                     recursionJson(je.getAsJsonObject(), j2j);
  155.                } else if(type.equals(JsonArray.class)) {
  156.                     // 集合型別
  157.                     // 重置集合資料,並獲取當前json元素的集合型別資訊
  158.                     deepLevel = 0;
  159.                     arrayType = new ArrayType();
  160.                     getJsonArrayType(je.getAsJsonArray());
  161.                     j2j.setArray(true);
  162.                     j2j.setArrayDeep(deepLevel);
  163.                     if(arrayType.getJo() != null) {
  164.                          j2j.setCustomClassName(StringUtils.firstToUpperCase(name));
  165.                          // 集合內的末點元素型別為自定義類, 遞迴
  166.                          recursionJson(arrayType.getJo(), j2j);
  167.                     } else {
  168.                          j2j.setType(arrayType.getType());
  169.                     }
  170.                     jsonBeans.add(j2j);
  171.                } else {
  172.                     // 其他情況,一般都是String,int等基礎資料型別
  173.                     j2j.setType(type);
  174.                     jsonBeans.add(j2j);
  175.                }
  176.           }
  177.      }
  178.      /**
  179.      * 集合深度,如果是3則為ArrayList<ArrayList<ArrayList<>>>
  180.      */
  181.      private static int deepLevel = 0;
  182.      /**
  183.      * 集合型別資料,用於儲存遞迴獲取到的集合資訊
  184.      */
  185.      private static ArrayType arrayType = new ArrayType();
  186.      /**
  187.      * 遞迴獲取集合的深度和型別等資訊
  188.      *
  189.      * @param jsonArray json集合資料
  190.      */
  191.      private static void getJsonArrayType(JsonArray jsonArray) {
  192.           // 每次遞迴,集合深度+1
  193.           deepLevel ++;
  194.           if (jsonArray.size() == 0) {
  195.                // 如果集合為空,則集合內元素型別無法判斷,直接設為Object
  196.                arrayType.setArrayDeep(deepLevel);
  197.                arrayType.setType(Object.class);
  198.           } else {
  199.                // 如果集合非空則取出第一個元素進行判斷
  200.                JsonElement childJe = jsonArray.get(0);
  201.                // 獲取json元素的型別
  202.                Class<?> type = getJsonType(childJe);
  203.                if(type == null) {
  204.                     // 自定義型別
  205.                     // 設定整個json物件,用於後續進行進一步解析處理
  206.                     arrayType.setJo(childJe.getAsJsonObject());
  207.                     arrayType.setArrayDeep(deepLevel);
  208.                } else if (type.equals(JsonArray.class)) {
  209.                     // 集合型別
  210.                     // 如果集合裡面還是集合,則遞迴本方法
  211.                     getJsonArrayType(childJe.getAsJsonArray());
  212.                } else {
  213.                     // 其他情況,一般都是String,int等基礎資料型別
  214.                     arrayType.setArrayDeep(deepLevel);
  215.                     arrayType.setType(type);
  216.                }
  217.           }
  218.      }
  219.      /**
  220.      * 獲取json元素的型別
  221.      *
  222.      * @param je json元素
  223.      * @return 型別
  224.      */
  225.      private static Class<?> getJsonType(JsonElement je) {
  226.           Class<?> clazz = null;
  227.           if(je.isJsonNull()) {
  228.                // 資料為null時,無法獲取型別,則視為object型別
  229.                clazz = Object.class;
  230.           } else if(je.isJsonPrimitive()) {
  231.                // primitive型別為基礎資料型別,如String,int等
  232.                clazz = getJsonPrimitiveType(je);
  233.           } else if(je.isJsonObject()) {
  234.                // 自定義型別引數則返回null,讓json的解析遞迴進行進一步處理
  235.                clazz = null;
  236.           } else if(je.isJsonArray()) {
  237.                // json集合型別
  238.                clazz = JsonArray.class;
  239.           }
  240.           return clazz;
  241.      }
  242.      /**
  243.      * 將json元素中的json基礎型別,轉換為String.class,int.class等具體的型別
  244.      *
  245.      * @param je json元素
  246.      * @return 具體資料型別,無法預估的型別統一視為Object.class型別
  247.      */
  248.      private static Class<?> getJsonPrimitiveType(JsonElement je) {
  249.           Class<?> clazz = Object.class;
  250.           JsonPrimitive jp = je.getAsJsonPrimitive();
  251.           // json中的型別會將數字集合成一個總的number型別,需要分別判斷
  252.           if(jp.isNumber()) {
  253.                String num = jp.getAsString();
  254.                if(num.contains(".")) {
  255.                     // 如果包含"."則為小數,先嚐試解析成float,如果失敗則視為double
  256.                     try {
  257.                          Float.parseFloat(num);
  258.                          clazz = float.class;
  259.                     } catch(NumberFormatException e) {
  260.                          clazz = double.class;
  261.                     }
  262.                } else {
  263.                     // 如果不包含"."則為整數,先嚐試解析成int,如果失敗則視為long
  264.                     try {
  265.                          Integer.parseInt(num);
  266.                          clazz = int.class;
  267.                     } catch(NumberFormatException e) {
  268.                          clazz = long.class;
  269.                     }
  270.                }
  271.           } else if(jp.isBoolean()) {
  272.                clazz = boolean.class;
  273.           } else if(jp.isString()) {
  274.                clazz = String.class;
  275.           }
  276.           // json中沒有其他具體型別如byte等
  277.           return clazz;
  278.      }
  279.      /**
  280.      * 獲取型別名稱字串
  281.      *
  282.      * @param j2j 轉換資料元素
  283.      * @return 型別名稱,無法獲取時,預設Object
  284.      */
  285.      private static String getTypeName(Json2JavaElement j2j) {
  286.           String name = "Object";
  287.           Class<?> type = j2j.getType();
  288.           if(j2j.getCustomClassName() != null && j2j.getCustomClassName().length() > 0) {
  289.                // 自定義類,直接用自定義的名稱customClassName
  290.                name = j2j.getCustomClassName();
  291.           } else {
  292.                // 非自定義類即可以獲取型別,解析型別class的名稱,如String.class就對應String
  293.                name = type.getName();
  294.                int lastIndexOf = name.lastIndexOf(".");
  295.                if(lastIndexOf != -1) {
  296.                     name = name.substring(lastIndexOf + 1);
  297.                }
  298.           }
  299.           // 如果集合深度大於0,則為集合資料,根據深度進行ArrayList巢狀
  300.           // 深度為3就是ArrayList<ArrayList<ArrayList<type>>>
  301.           StringBuilder sb = new StringBuilder();
  302.           for(int i=0; i<j2j.getArrayDeep(); i++) {
  303.                sb.append("ArrayList<");
  304.           }
  305.           sb.append(name);
  306.           for(int i=0; i<j2j.getArrayDeep(); i++) {
  307.                sb.append(">");
  308.           }
  309.           return sb.toString();
  310.      }
  311. }
複製程式碼


----------------------------------------------------------------------

問題
對於陣列資料,其中元素的型別只會取第一個資料進行解析,
如果json字串中資料內第一個資料不全或者資料為空,即無法獲取
對於此類無法獲取資料值造成無法判斷型別的情況,都預設設為了Object型別

----------------------------------------------------------------------

歡迎Github上star和follow, 多個高質量原始碼等待著你
也可以在eoeandroid論壇主頁中進入我個人中心,檢視我其他主題帖子,篇篇高質量,你值得信賴