開源項目JCG,運行時json轉class並支持添加註解

關注“Java藝術”一起來充電吧!

JCG(json-class-generator)是一個可用於運行時根據json生成class的工具,可能使用場景不多。由於是運行時生成的class,所以生成的class也只能通過反射去使用。

技術棧

  • gsonjson解析工具;

  • asm:字節碼生成工具;


特性

  • json解析生成class,爲class添加字段和對應字段的getset方法;

  • 支持爲生成的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上;

如果參數2ElementType.TYPE,參數3"",那麼結果就是在json生成的class上添加註解;如果參數2ElementType.FIELD,參數3""則會報錯,但如果參數3"name",則是在name字段上添加註解。

在前面給出的json例子中,由於nodes字段是一個數組,且數組元素不是基本數據類型,因此JCG也會爲數組元素生成一個class。如果想爲nodes元素類型對應的class也添加註解,那麼可以通過path實現。例如:

  • 參數2ElementType.TYPE,參數3"nodes",則會在nodes元素對應的類上添加註解;

  • 參數2ElementType.FIELD,參數3"nodes",則只是在nodes字段上添加註解;

  • 參數2ElementType.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);
    }

}

註解規則映射類AnnotationRuleputAttr方法說明:

  • 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$$NodesJCGjson中的nodes字段生成的一個class

公衆號:Java藝術

掃碼關注最新動態

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章