Jdeparser学习笔记

Wesley13
• 阅读 534

Jdeparser学习笔记

Jdeparser简介

Jdeparser是JBOSS社区提供的Java源代码生成工具,可以方便生成Java源代码,常用于Annotation Processing中。

Jdeparser常用类

JDeparser

JDeparser类是JDeparser的入口,通过调用createSources函数创建JSources(源码容器)

JSources

JSources是源码容器,通过createSourceFile函数可以创建JSourceFile(源码文件)

JSourceFile

JSourceFile是源码文件,该类包含以下几个函数,用于创建源文件具体内容:

  1. _import 生成iimport语句
  2. importStatic 生成import语句(import类中的静态变量)
  3. blankLine 添加一个空行
  4. _class 生成class
  5. _enum 生成枚举类型
  6. _interface 生成接口
  7. annotationInterface 生成注解接口

_class, _enum, _interface, annotationInterface四个函数会返回JClassDef对象

JClassDef

JClassDef是类定义, 通过该类的一系列函数完成类具体内容定义:

  1. _extends 类继承哪个类
  2. _implements 类实现哪些接口
  3. erasedType 获取当前类擦除类型后的类型
  4. genericType 获取当前
  5. _enum 生成枚举值(该函数不会生成name, 可能是一个bug)
  6. typeParam 生成泛型信息
  7. method 生成方法
  8. annotate 生成类上的注解
  9. field 生成类属性
  10. constructor 生成构造函数
  11. staticInit 生成static静态代码块
  12. init 生成代码块(与staticInit不同, 每次new的时候都会执行init, 看看成构造函数的一部分)

Filer

文件编档员,用于存储JSources, 比如存储JSources到文件, 或者存储到ByteArrayOutputStream中

    private final JFiler filer = new JFiler() {
        public OutputStream openStream(final String packageName, final String fileName) throws IOException {
            final Key key = new Key(packageName, fileName + ".java");
            if (!sourceFiles.containsKey(key)) {
                final ByteArrayOutputStream stream = new ByteArrayOutputStream();
                if (sourceFiles.putIfAbsent(key, stream) == null) {
                    return stream;
                }
            }
            throw new IOException("Already exists");
        }
    };

FormatPreferences

生成源文件的格式配置, 比如空格个数等

组件示例

生成一个类

JSources sources = JDeparser.createSources(getFiler(), new FormatPreferences());
JSourceFile bazFile = sources.createSourceFile("org.foo.bar", "Baz");

导入类

#import java.math.BigDecimal;
bazFile._import(BigDecimal.class);

生成类

//@Controller
//public class Baz<T extends String> extends XXClass implements XXInterface1, XXInterface2{}
JClassDef classDef = bazFile._class(JMod.PUBLIC, "Baz");
classDef.typeParam("T")._extends(String.class);
classDef._extends("XXClass");
classDef._implements("XXInterface1", "XXInterface2");
classDef.annotate("Controller");

生成函数声明

//public String <T extends Thread> foo(T param1, String[] param2, Object... params) throws Exception {}
public static final int VARARGS = 1 << 31; // JMod.VARARGS不是public的,不能访问
JMethodDef methodDef = classDef.method(JMod.PUBLIC, String.class, "foo");
methodDef.typeParam("T")._extends(Thread.class);
methodDef.param(JMod.FINAL, "T", "param1");
methodDef.param(0 , String[].class.getCanonicalName(), "param2");
methodDef.param(JMod.FINAL | VARARGS, Object.class, "params");
methodDef._throws(Exception.class);

生成属性

// private static final String DEFAULT_VALUE = "ONE";
classDef.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, String.class, "DEFAUL_VALUE", JExprs.str("ONE"));

生成函数体

JBlock body = methodDef.body();
body.xxx

生成if语句

/**
if (var1 == null) {
    var1 = "var1 value";
    if (var1.startWith("var1")) {
        System.out.println(var1);
        return;
    } else if (var1.startWith("var1")) {
        var1 = "var2 value";
        return;
    }
}
**/
JIf if1 = body._if(JExprs.$v(var1).eq(JExpr.NULL));
if1.assign(JExprs.$v(var1), JExprs.str("var1 value"));

JIf if1_1 = if1._if(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
if1_1.call(JTypes.$t(System.class).$v("out"), "println").arg(JExprs.$v(var1));
if1_1._return();

JIf if2 = if1.elseIf(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));

JBlock block = if1._else();

注意: if1可以调用elseIf也可以调用_esle, 但是不能两者都调用, 只能调用其中一个, 否则会报错(这里是否有改进的空间)

生成for语句

//foreach方式 for(String tmp : var1)  var1需要可迭代
body.forEach(0, String.class, "tmp", JExprs.$v(var1));

//for形式 for (int tmp = 0; tmp <= 10; tmp++) {}
JFor for1 = body._for();
JVarDeclaration testVar = for1.init(0, int.class, "tmp", JExprs.decimal(0));
for1.test(JExprs.$v(testVar).le(JExprs.decimal(10)));
for1.update(JExprs.$v(testVar).postInc());

生成while语句

//java.sql.ResultSet resultSet = stmt.executeQuery("select * from xx");
//while (resultSet.next() == true) {}
JCall queryCall = JExprs.$v("stmt").call("executeQuery").arg(JExprs.str("select * from xx"));
JVarDeclaration resultSet = body.var(0, ResultSet.class, "resultSet", queryCall);
JBlock whileBlock = body._while(JExprs.$v(resultSet).call("next").eq(JExpr.TRUE));

//do {
//    i++;
//} while (i<10);
JBlock doBlock = body._do(JExprs.$v("i<10"));
doBlock.add(JExprs.$v("i").postInc());

方法调用

//调用startWith函数, var1.startWith("var1")
JExprs.$v(var1).call("startWith").arg(JExprs.str("var1"))

生成注释

classDef.docComment().htmlTag("ul", true).attribute("class", "banana").htmlTag("li", false).text("A line item");
classDef.docComment().docTag("author", "Someone");
methodDef.blockComment().text("块注释");
var1.lineComment().text("行注释").nl();

较为完整的例子

代码如下;

import org.jboss.jdeparser.*;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.sql.ResultSet;

public class SimpleExampleTestCase extends AbstractGeneratingTestCase {
    public static final int VARARGS            = 1 << 31;


    @Test
    public void testSimple() throws IOException {

        final JSources sources = JDeparser.createSources(getFiler(), new FormatPreferences());
        final JSourceFile bazFile = sources.createSourceFile("org.foo.bar", "Baz");

        bazFile._import(BigDecimal.class);

        final JClassDef classDef = bazFile._class(JMod.PUBLIC, "Baz");
        classDef.docComment().htmlTag("ul", true).attribute("class", "banana").htmlTag("li", false).text("A line item");
        classDef.docComment().docTag("author", "Someone");

        classDef.typeParam("T")._extends(String.class);
        classDef._extends("XXClass");
        classDef._implements("XXInterface1", "XXInterface2");
        classDef.annotate("Controller");

       JVarDeclaration var = classDef.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, String.class, "DEFAUL_VALUE", JExprs.str("ONE"));
        //var.add("ddd", JExpr.NULL);

        JMethodDef methodDef = classDef.method(JMod.PUBLIC, String.class, "foo");
        methodDef.blockComment().text("块注释");
        ///methodDef.docComment().docTag("Date", "20190101");

        methodDef.typeParam("T")._extends(String.class);
        methodDef.param(JMod.FINAL , "T", "param1");
        methodDef.param(0 , String[].class.getCanonicalName(), "param2");
        methodDef.param(JMod.FINAL | VARARGS, Object.class, "params");
        methodDef._throws(Exception.class);

        JBlock body = methodDef.body();

        JVarDeclaration var1 = body.var(0, String.class, "var1", JExpr.NULL);
        var1.lineComment().text("行注释").nl();
        JIf if1 = body._if(JExprs.$v(var1).eq(JExpr.NULL));
        if1.assign(JExprs.$v(var1), JExprs.str("var1 value"));

        JIf if1_1 = if1._if(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
        if1_1.call(JTypes.$t(System.class).$v("out"), "println").arg(JExprs.$v(var1));
        if1_1._return();
        JIf if2 = if1.elseIf(JExprs.$v(var1).call("startWith").arg(JExprs.str("var1")));
        if2.assign(JExprs.$v(var1), JExprs.str("var2 value"));
        if2._return();
//        JBlock block = if1._else();
//        block.assign(JExprs.$v(var1), JExprs.str("var3 value"));


        body.forEach(0, String.class, "tmp", JExprs.$v(var1));
        JFor for1 = body._for();
        JVarDeclaration testVar = for1.init(0, int.class, "tmp", JExprs.decimal(0));
        for1.test(JExprs.$v(testVar).le(JExprs.decimal(10)));
        for1.update(JExprs.$v(testVar).postInc());

        JCall queryCall = JExprs.$v("stmt").call("executeQuery").arg(JExprs.str("select * from xx"));
        JVarDeclaration resultSet = body.var(0, ResultSet.class, "resultSet", queryCall);
        JBlock whileBlock = body._while(JExprs.$v(resultSet).call("next").eq(JExpr.TRUE));


       JBlock doBlock = body._do(JExprs.$v("i<10"));
       doBlock.add(JExprs.$v("i").postInc());
       
        sources.writeSources();
        final ByteArrayInputStream inputStream = openFile("org.foo.bar", "Baz.java");
        final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
}

输出结果如下;

package org.foo.bar;

import java.math.BigDecimal;

/**

 * <ul class="banana">
 *   <li>A line item
 * @author Someone

 */
@Controller
public class Baz<T extends String> extends XXClass implements XXInterface1, XXInterface2 {
    private static final String DEFAUL_VALUE = "ONE";
    /*
     * 块注释
     */
    public <T extends String> String foo(final T param1, String[] param2, final Object... params) throws Exception {
        // 行注释
        String var1 = null;
        if (var1 == null) {
            var1 = "var1 value";
            if (var1.startWith("var1")) {
                System.out.println(var1);
                return;
            }
        } else if (var1.startWith("var1")) {
            var1 = "var2 value";
            return;
        }
        for (String tmp : var1) {}
        for (int tmp = 0; tmp <= 10; tmp++) {}
        java.sql.ResultSet resultSet = stmt.executeQuery("select * from xx");
        while (resultSet.next() == true) {}
        do {
            i++;
        } while (i<10);
    }
}
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
java基础知识随身记
2018年11月12日20:51:35一、基础知识:1、JVM、JRE和JDK的区别:JVM(JavaVirtualMachine):java虚拟机,用于保证java的跨平台的特性。  java语言是跨平台,jvm不是跨平台的。JRE(JavaRuntimeEnvironment):java的运行环境,包括jvmjava的核心类
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这