自動根據json字串生成javabean類
阿新 • • 發佈:2019-02-14
寫錯了一個型別,然後各種崩潰
寫錯了一個變數名無法解析
...
程式碼工具來啦~
自動生成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的程式碼
-
package utils;
-
import java.io.File;
-
import java.util.ArrayList;
-
import java.util.Iterator;
-
import java.util.List;
-
import java.util.Map.Entry;
-
import com.google.gson.JsonArray;
-
import com.google.gson.JsonElement;
-
import com.google.gson.JsonObject;
-
import com.google.gson.JsonParser;
-
import com.google.gson.JsonPrimitive;
-
import entity.ArrayType;
-
import entity.Json2JavaElement;
-
public class JsonUtils {
-
public static void main(String[] args) {
-
parseJson2Java();
-
}
-
/**
-
* 將json字串轉換為對應的javabean
-
*
-
* <p>
-
* 用法:<br>
-
* 將json字串拷貝至本專案中/Json/JsonString.txt 檔案中去,然後呼叫該方法,<br>
-
* 就會在本專案中/Json/JsonBean.java中生成一個對應的JavaBean類<br><br>
-
* 注意:<br>
-
* 如果json字串中有null或者空集合[]這種無法判斷型別的,會統一使用Object型別
-
*/
-
public static void parseJson2Java() {
-
/// 讀取json字串
-
String string = FileUtils.readToString(new File("Json\\JsonString.txt"), "UTF-8");
-
// 解析獲取整個json結構集合
-
JsonParser parser = new JsonParser();
-
JsonElement element = parser.parse(string);
-
JsonObject jo = element.getAsJsonObject();
-
List<Json2JavaElement> jsonBeanTree = getJsonBeanTree(jo);
-
// 利用獲取到的json結構集合,建立對應的javabean檔案內容
-
String javaBeanStr = createJavaBean(jsonBeanTree);
-
// 將生成的內容寫入到檔案中去
-
FileUtils.writeString2File(javaBeanStr, new File("Json\\JsonBean.java"));
-
}
-
/**
-
* 根據解析好的資料建立生成對應的javabean類字串
-
*
-
* @param jsonBeanTree 解析好的資料集合
-
* @return 生成的javabean類字串
-
*/
-
private static String createJavaBean(List<Json2JavaElement> jsonBeanTree) {
-
StringBuilder sb = new StringBuilder();
-
// 是否包含自定義子類
-
boolean hasCustomeClass = false;
-
List<String> customClassNames = new ArrayList<String>();
-
sb.append("public class JsonBeans {\n");
-
// 由於在迴圈的時候有移除操作,所以使用迭代器遍歷
-
Iterator<Json2JavaElement> iterator = jsonBeanTree.iterator();
-
while(iterator.hasNext()) {
-
Json2JavaElement j2j = iterator.next();
-
// 儲存自定義類名稱至集合中,注意已經包含的不再新增
-
if(j2j.getCustomClassName() != null && !customClassNames.contains(j2j.getCustomClassName())) {
-
customClassNames.add(j2j.getCustomClassName());
-
}
-
if(j2j.getParentJb() != null) {
-
// 如果有parent,則為自定義子類,設定識別符號不做其他操作
-
hasCustomeClass = true;
-
} else {
-
// 如果不是自定義子類,則根據型別名和控制元件物件名生成變數申明語句
-
// private TextView tv_name;
-
sb.append("\tprivate ")
-
.append(getTypeName(j2j))
-
.append(" ")
-
.append(j2j.getName())
-
.append(";\n");
-
// 已經使用的資料會移除,則集合中只會剩下自定義子類相關的元素資料,將在後續的迴圈中處理
-
iterator.remove();
-
}
-
}
-
// 設定所有自定義類
-
if(hasCustomeClass) {
-
for(String customClassName : customClassNames) {
-
// 根據名稱申明子類
-
// /*sub class*/
-
// public class CustomClass {
-
sb.append("\n\t/*sub class*/\n");
-
sb.append("\tpublic class ")
-
.append(customClassName)
-
.append(" {\n");
-
// 迴圈餘下的集合
-
Iterator<Json2JavaElement> customIterator = jsonBeanTree.iterator();
-
while(customIterator.hasNext()) {
-
Json2JavaElement j2j = customIterator.next();
-
// 根據當前資料的parent名稱,首字母轉為大寫生成parent的類名
-
String parentClassName = StringUtils.firstToUpperCase(j2j.getParentJb().getName());
-
// 如果當前資料屬於本次外層迴圈需要處理的子類
-
if(parentClassName.equals(customClassName)) {
-
// 根據型別名和控制元件物件名生成變數申明語句
-
// private TextView tv_name;
-
sb.append("\t\tprivate ")
-
.append(getTypeName(j2j))
-
.append(" ")
-
.append(j2j.getName())
-
.append(";\n");
-
// 已經使用的資料會移除,減少下一次外層迴圈的遍歷次數
-
customIterator.remove();
-
}
-
}
-
sb.append("\t}\n");
-
}
-
}
-
sb.append("}");
-
return sb.toString();
-
}
-
/**
-
* 遞迴遍歷整個json資料結構,儲存至jsonBeans集合中
-
*
-
* @param rootJo 根json物件
-
* @return 解析好的資料集合
-
*/
-
private static List<Json2JavaElement> getJsonBeanTree(JsonObject rootJo) {
-
jsonBeans = new ArrayList<Json2JavaElement>();
-
recursionJson(rootJo, null);
-
return jsonBeans;
-
}
-
/**
-
* 儲存遞迴獲取到資料的集合
-
*/
-
private static List<Json2JavaElement> jsonBeans = new ArrayList<Json2JavaElement>();
-
/**
-
* 遞迴獲取json資料
-
*
-
* @param jo 當前遞迴解析的json物件
-
* @param parent 已經解析好的上一級資料,無上一級時傳入null
-
*/
-
private static void recursionJson(JsonObject jo, Json2JavaElement parent) {
-
// 迴圈整個json物件的鍵值對
-
for (Entry<String, JsonElement> entry : jo.entrySet()) {
-
// json物件的鍵值對建構為 {"key":value}
-
// 其中,值可能是基礎型別,也可能是集合或者物件,先解析為json元素
-
String name = entry.getKey();
-
JsonElement je = entry.getValue();
-
Json2JavaElement j2j = new Json2JavaElement();
-
j2j.setName(name);
-
if(parent != null) {
-
j2j.setParentJb(parent);
-
}
-
// 獲取json元素的型別,可能為多種情況,如下
-
Class<?> type = getJsonType(je);
-
if(type == null) {
-
// 自定義型別
-
// json鍵值的首字母轉為大寫,作為自定義類名
-
j2j.setCustomClassName(StringUtils.firstToUpperCase(name));
-
// ?
-
j2j.setSouceJo(je.getAsJsonObject());
-
jsonBeans.add(j2j);
-
// 自定義類需要繼續遞迴,解析自定義類中的json結構
-
recursionJson(je.getAsJsonObject(), j2j);
-
} else if(type.equals(JsonArray.class)) {
-
// 集合型別
-
// 重置集合資料,並獲取當前json元素的集合型別資訊
-
deepLevel = 0;
-
arrayType = new ArrayType();
-
getJsonArrayType(je.getAsJsonArray());
-
j2j.setArray(true);
-
j2j.setArrayDeep(deepLevel);
-
if(arrayType.getJo() != null) {
-
j2j.setCustomClassName(StringUtils.firstToUpperCase(name));
-
// 集合內的末點元素型別為自定義類, 遞迴
-
recursionJson(arrayType.getJo(), j2j);
-
} else {
-
j2j.setType(arrayType.getType());
-
}
-
jsonBeans.add(j2j);
-
} else {
-
// 其他情況,一般都是String,int等基礎資料型別
-
j2j.setType(type);
-
jsonBeans.add(j2j);
-
}
-
}
-
}
-
/**
-
* 集合深度,如果是3則為ArrayList<ArrayList<ArrayList<>>>
-
*/
-
private static int deepLevel = 0;
-
/**
-
* 集合型別資料,用於儲存遞迴獲取到的集合資訊
-
*/
-
private static ArrayType arrayType = new ArrayType();
-
/**
-
* 遞迴獲取集合的深度和型別等資訊
-
*
-
* @param jsonArray json集合資料
-
*/
-
private static void getJsonArrayType(JsonArray jsonArray) {
-
// 每次遞迴,集合深度+1
-
deepLevel ++;
-
if (jsonArray.size() == 0) {
-
// 如果集合為空,則集合內元素型別無法判斷,直接設為Object
-
arrayType.setArrayDeep(deepLevel);
-
arrayType.setType(Object.class);
-
} else {
-
// 如果集合非空則取出第一個元素進行判斷
-
JsonElement childJe = jsonArray.get(0);
-
// 獲取json元素的型別
-
Class<?> type = getJsonType(childJe);
-
if(type == null) {
-
// 自定義型別
-
// 設定整個json物件,用於後續進行進一步解析處理
-
arrayType.setJo(childJe.getAsJsonObject());
-
arrayType.setArrayDeep(deepLevel);
-
} else if (type.equals(JsonArray.class)) {
-
// 集合型別
-
// 如果集合裡面還是集合,則遞迴本方法
-
getJsonArrayType(childJe.getAsJsonArray());
-
} else {
-
// 其他情況,一般都是String,int等基礎資料型別
-
arrayType.setArrayDeep(deepLevel);
-
arrayType.setType(type);
-
}
-
}
-
}
-
/**
-
* 獲取json元素的型別
-
*
-
* @param je json元素
-
* @return 型別
-
*/
-
private static Class<?> getJsonType(JsonElement je) {
-
Class<?> clazz = null;
-
if(je.isJsonNull()) {
-
// 資料為null時,無法獲取型別,則視為object型別
-
clazz = Object.class;
-
} else if(je.isJsonPrimitive()) {
-
// primitive型別為基礎資料型別,如String,int等
-
clazz = getJsonPrimitiveType(je);
-
} else if(je.isJsonObject()) {
-
// 自定義型別引數則返回null,讓json的解析遞迴進行進一步處理
-
clazz = null;
-
} else if(je.isJsonArray()) {
-
// json集合型別
-
clazz = JsonArray.class;
-
}
-
return clazz;
-
}
-
/**
-
* 將json元素中的json基礎型別,轉換為String.class,int.class等具體的型別
-
*
-
* @param je json元素
-
* @return 具體資料型別,無法預估的型別統一視為Object.class型別
-
*/
-
private static Class<?> getJsonPrimitiveType(JsonElement je) {
-
Class<?> clazz = Object.class;
-
JsonPrimitive jp = je.getAsJsonPrimitive();
-
// json中的型別會將數字集合成一個總的number型別,需要分別判斷
-
if(jp.isNumber()) {
-
String num = jp.getAsString();
-
if(num.contains(".")) {
-
// 如果包含"."則為小數,先嚐試解析成float,如果失敗則視為double
-
try {
-
Float.parseFloat(num);
-
clazz = float.class;
-
} catch(NumberFormatException e) {
-
clazz = double.class;
-
}
-
} else {
-
// 如果不包含"."則為整數,先嚐試解析成int,如果失敗則視為long
-
try {
-
Integer.parseInt(num);
-
clazz = int.class;
-
} catch(NumberFormatException e) {
-
clazz = long.class;
-
}
-
}
-
} else if(jp.isBoolean()) {
-
clazz = boolean.class;
-
} else if(jp.isString()) {
-
clazz = String.class;
-
}
-
// json中沒有其他具體型別如byte等
-
return clazz;
-
}
-
/**
-
* 獲取型別名稱字串
-
*
-
* @param j2j 轉換資料元素
-
* @return 型別名稱,無法獲取時,預設Object
-
*/
-
private static String getTypeName(Json2JavaElement j2j) {
-
String name = "Object";
-
Class<?> type = j2j.getType();
-
if(j2j.getCustomClassName() != null && j2j.getCustomClassName().length() > 0) {
-
// 自定義類,直接用自定義的名稱customClassName
-
name = j2j.getCustomClassName();
-
} else {
-
// 非自定義類即可以獲取型別,解析型別class的名稱,如String.class就對應String
-
name = type.getName();
-
int lastIndexOf = name.lastIndexOf(".");
-
if(lastIndexOf != -1) {
-
name = name.substring(lastIndexOf + 1);
-
}
-
}
-
// 如果集合深度大於0,則為集合資料,根據深度進行ArrayList巢狀
-
// 深度為3就是ArrayList<ArrayList<ArrayList<type>>>
-
StringBuilder sb = new StringBuilder();
-
for(int i=0; i<j2j.getArrayDeep(); i++) {
-
sb.append("ArrayList<");
-
}
-
sb.append(name);
-
for(int i=0; i<j2j.getArrayDeep(); i++) {
-
sb.append(">");
-
}
-
return sb.toString();
-
}
- }
----------------------------------------------------------------------
問題
對於陣列資料,其中元素的型別只會取第一個資料進行解析,
如果json字串中資料內第一個資料不全或者資料為空,即無法獲取
對於此類無法獲取資料值造成無法判斷型別的情況,都預設設為了Object型別
----------------------------------------------------------------------
歡迎Github上star和follow, 多個高質量原始碼等待著你
也可以在eoeandroid論壇主頁中進入我個人中心,檢視我其他主題帖子,篇篇高質量,你值得信賴