關注“Java藝術”一起來充電吧!
JCG
(json-class-generator
)是一個可用於運行時根據json
生成class
的工具,可能使用場景不多。由於是運行時生成的class
,所以生成的class
也只能通過反射去使用。
技術棧
gson
:json
解析工具;asm
:字節碼生成工具;
特性
將
json
解析生成class
,爲class
添加字段和對應字段的get
、set
方法;支持爲生成的
class
添加註解,使用註解規則聲明將註解添加在類或是字段上;
基礎功能:將json解析生成class
爲驗證結果的正確性,可配置將本工具包生成的class
輸出到文件,通過idea
打開可以查看生成的java
代碼。
public class JsonToClassTest {
static {
// value爲輸出的目錄
System.setProperty("jcg.classSavaPath", "/Users/wjy/MyProjects/JsonClassGenerator");
}
}
既然要用到動態json
解析生成class
,那麼說明json
我們是通過API
或者讀取數據庫獲取的。爲了簡單,我們就直接定義json
字符串來測試了。
假設json
爲:
{
"name":"name",
"price":1.0,
"nodes":[
{
"id":222,
"note":"xxx"
}
]
}
那麼我們期望JCG
工具爲我們生成的class
應該是這樣的:
public class Xxx {
private String name;
private BigDecimal price;
private List<Yyy> nodes;
// get、set方法省略
}
public class Yyy {
private Integer id;
private String note;
// get、set方法省略
}
現在我們開始使用JCG
工具將上面例子中的json
解析生成class
public class JsonToClassTest {
static {
System.setProperty("jcg.classSavaPath", "/Users/wjy/MyProjects/JsonClassGenerator");
}
@Test
public void test() {
String json = "{\"name\":\"offer name\",\"price\":1.0,\"nodes\":[{\"id\":222,\"note\":\"xxx\"}]}";
String className = "com.wujiuye.jcg.model.TestBean";
// 我們需要爲這串json定義一個類型名,
// 然後調用JcgClassFactory的generateResponseClassByJson方法即可生成Class
Class<?> cls = JcgClassFactory.getInstance()
.generateResponseClassByJson(className, json);
try {
// 驗證生成的class是否正確
Object obj = new Gson().fromJson(json, cls);
System.out.println(obj.getClass());
// 驗證生成的get/set方法是否能正常調用
Method method = obj.getClass().getDeclaredMethod("getNodes");
Object result = method.invoke(obj);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
結果省略。
特色:爲生成的class添加註解
爲了使用某些框架的特性,我們可能需要在將json
解析生成class
時,就需要爲class
添加註解。比如我們想將JCG
生成的class
用於後續的json
解析,那麼我們可能需要在class
上或者字段上添加一些諸如@JsonIgnore
之類的註解。這些需求JCG
都可以滿足,目前的不足之處是還不支持註解的屬性是數組類型。
假設,我們想在解析json
生成的class
上添加一個@TestAnnno
註解,可以這麼實現:
public class JsonToClassTest {
static {
System.setProperty("jcg.classSavaPath", "/Users/wjy/MyProjects/JsonClassGenerator");
}
@Test
public void test() {
String json = "{\"name\":\"offer name\",\"price\":1.0,\"nodes\":[{\"id\":222,\"note\":\"xxx\"}]}";
String className = "com.wujiuye.jcg.model.TestBean";
// 註解規則
AnnotationRule annotationRule = new AnnotationRule(TestAnno.class, ElementType.TYPE, "");
annotationRule.putAttr("value", "122");
// 註冊註解規則
AnnotationRuleRegister.registRule(className, annotationRule);
// 調用JcgClassFactory的generateResponseClassByJson方法即可生成Class
Class<?> cls = JcgClassFactory.getInstance()
.generateResponseClassByJson(className, json);
}
}
註解規則映射類AnnotationRule
的構造方法說明:
參數
1
:要添加的註解的類型;參數
2
:註解在類上還是字段上,第二個參數和第三個參數需要配合使用。(只支持添加在類上、添加在字段上兩種類型);參數
3
:添加的路徑,JCG
根據路徑通過深度遍歷尋找目標字段,如果是添加在類上,則會加在目錄字段對應的class
上;
如果參數2
爲ElementType.TYPE
,參數3
爲""
,那麼結果就是在json
生成的class
上添加註解;如果參數2
爲ElementType.FIELD
,參數3
爲""
則會報錯,但如果參數3
爲"name"
,則是在name
字段上添加註解。
在前面給出的json
例子中,由於nodes
字段是一個數組,且數組元素不是基本數據類型,因此JCG
也會爲數組元素生成一個class
。如果想爲nodes
元素類型對應的class
也添加註解,那麼可以通過path
實現。例如:
參數
2
爲ElementType.TYPE
,參數3
爲"nodes"
,則會在nodes
元素對應的類上添加註解;參數
2
爲ElementType.FIELD
,參數3
爲"nodes"
,則只是在nodes
字段上添加註解;參數
2
爲ElementType.FIELD
,參數3
爲"nodes.id"
,則會在nodes
元素對應的類的id
字段上添加註解;
代碼如下:
public class JsonToClassTest {
static {
System.setProperty("jcg.classSavaPath", "/Users/wjy/MyProjects/JsonClassGenerator");
}
@Test
public void test() {
String json = "{\"name\":\"offer name\",\"price\":1.0,\"nodes\":[{\"id\":222,\"note\":\"xxx\"}]}";
String className = "com.wujiuye.jcg.model.TestBean";
// 給nodes數組的元素類型class添加@TestAnno
AnnotationRule fieldRule = new AnnotationRule(TestAnno.class, ElementType.TYPE, "nodes");
fieldRule.putAttr("value", "12233");
AnnotationRuleRegister.registRule(className, fieldRule);
// 給nodes數組元素類型class的id字段添加註解@TestAnno
AnnotationRule fieldClassRule = new AnnotationRule(TestAnno.class, ElementType.FIELD, "nodes.id");
fieldClassRule.putAttr("type", ElementType.FIELD);
AnnotationRuleRegister.registRule(className, fieldClassRule);
// 調用JcgClassFactory的generateResponseClassByJson方法即可生成Class
Class<?> cls = JcgClassFactory.getInstance()
.generateResponseClassByJson(className, json);
}
}
註解規則映射類AnnotationRule
的putAttr
方法說明:
key
: 對應註解的屬性名;value
: 對應註解的屬性值,屬性值必須是基本數據類型、String
、枚舉、註解,目前不支持數組;
如果註解的屬性也是註解類型,那麼可以通過putAttr
方法給AnnotationRule
添加一個AnnotationRule
實現,代碼如下:
public class JsonToClassTest {
static {
System.setProperty("jcg.classSavaPath", "/Users/wjy/MyProjects/JsonClassGenerator");
}
@Test
public void test() {
String json = "{\"name\":\"offer name\",\"price\":1.0,\"nodes\":[{\"id\":222,\"note\":\"xxx\"}]}";
String className = "com.wujiuye.jcg.model.TestBean";
AnnotationRule fieldRule = new AnnotationRule(TestAnno.class, ElementType.TYPE, "nodes");
fieldRule.putAttr("value", "12233");
// 設置@TestAnno的map屬性,該屬性類型爲註解類型
AnnotationRule annoRule = new AnnotationRule(Map.class, null, "");
annoRule.putAttr("value", "haha");
//
fieldRule.putAttr("map", annoRule);
AnnotationRuleRegister.registRule(className, fieldRule);
// 調用JcgClassFactory的generateResponseClassByJson方法即可生成Class
Class<?> cls = JcgClassFactory.getInstance()
.generateResponseClassByJson(className, json);
}
}
生成的結果如下:
@TestAnno(
value = "12233",
map = @Map("haha")
)
public class TestBean$$Nodes {
private Integer id;
private String note;
// get/set省略
}
TestBean$$Nodes
是JCG
爲json
中的nodes
字段生成的一個class
。
公衆號:Java藝術
掃碼關注最新動態