lemon geci_创建一个Java :: Geci生成器

lemon geci

几天前,我写了有关Java :: Geci架构,代码生成原理以及生成Java源代码的可能不同方式的文章。

在本文中,我将讨论在Java :: Geci中创建生成器有多么简单。

您好,Wold生成器

HelloWorld1

最简单的生成器是Hello, World! 发电机。 这将生成一个打印Hello, World!的方法Hello, World! 到标准输出。 要创建此生成器,Java类必须实现Generator接口。 生成器的整个代码为:

package javax0.geci.tutorials.hello;import javax0.geci.api.GeciException;
import javax0.geci.api.Generator;
import javax0.geci.api.Source;public class HelloWorldGenerator1 implements Generator {public void process(Source source) {try {final var segment = source.open("hello");segment.write_r("public static void hello(){");segment.write("System.out.println(\"Hello, World\");");segment.write_l("}");} catch (Exception e) {throw new GeciException(e);}}
}

这确实是整个生成器类。 没有简化或删除的行。 当框架找到需要方法hello()的文件时,它将调用process()

方法process ()查询名为“ hello”的段。 这是指线

//<editor-fold id="hello">//</editor-fold>

在源代码中。 segment对象可用于将行写入代码。 write()方法write()一行。 方法write_r()也会写一行,但是它也表示必须缩进该行之后的行。 相反的是write_l() ,该信号指示已经将此行和连续的行重新制表回到先前的位置。

要使用生成器,我们应该有一个需要它的类。 这是

package javax0.geci.tutorials.hello;public class HelloWorld1 {//<editor-fold id="hello">//</editor-fold>
}

我们还需要一个测试,该测试将在每次编译代码并运行单元测试时运行代码生成:

package javax0.geci.tutorials.hello;import javax0.geci.engine.Geci;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;import static javax0.geci.api.Source.maven;public class TestHelloWorld1 {@Test@DisplayName("Start code generator for HelloWorld1")void testGenerateCode() throws Exception {Assertions.assertFalse(new Geci().only("^.*/HelloWorld1.java$").register(new HelloWorldGenerator1()).generate(), Geci.FAILED);}
}

执行代码后,将修改文件HelloWorld1.java并将在编辑器折叠之间插入以下行:

package javax0.geci.tutorials.hello;public class HelloWorld1 {//<editor-fold id="hello">public static void hello(){System.out.println("Hello, World");}//</editor-fold>
}

这是一个非常简单的示例,我们可以进一步发展。

HelloWorld2

该示例中低于标准的一件事是,生成器的范围在调用only()方法的测试中受到限制。 让框架扫描所有文件并选择本身以某种方式表明它们需要生成器服务的源文件是一种更好的做法。 在“你好,世界!”的情况下 生成器,它可以是hello段的存在,作为源代码中的编辑器折叠。 如果存在,则代码需要方法hello() ,否则不需要。 我们可以通过这种方式实现生成器的第二个版本。 我们还修改了实现,而不仅仅是修改了接口Generator ,而是扩展了抽象类AbstractGeneratorEx 。 名称中的后缀Ex表示该类为我们处理异常。 该抽象类实现方法process()并调用要定义的processEx() ,该签名具有与process()相同的签名,但允许抛出异常。 如果发生这种情况,则将其封装在GeciException ,就像我们在第一个示例中所做的那样。

该代码将如下所示:

package javax0.geci.tutorials.hello;import javax0.geci.api.Source;
import javax0.geci.tools.AbstractGeneratorEx;import java.io.IOException;public class HelloWorldGenerator2 extends AbstractGeneratorEx {public void processEx(Source source) throws IOException {final var segment = source.open("hello");if (segment != null) {segment.write_r("public static void hello(){");segment.write("System.out.println(\"Hello, World\");");segment.write_l("}");}}
}

尽管它正在检查段的存在,但它甚至比第一个简单。 当代码调用source.open("hello") ,如果源代码中没有名为hello段,则该方法将返回null 。 使用第二个生成器的实际代码与第一个相同。 当我们在代码库中运行两个测试时,它们都会生成代码,所幸的是相同的。

调用第二个生成器的测试是

package javax0.geci.tutorials.hello;import javax0.geci.engine.Geci;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;import static javax0.geci.api.Source.maven;public class TestHelloWorld2 {@Test@DisplayName("Start code generator for HelloWorld2")void testGenerateCode() throws Exception {Assertions.assertFalse(new Geci().register(new HelloWorldGenerator2()).generate(), Geci.FAILED);}
}

请注意,这一次我们不需要限制调用only()方法的代码扫描。 同样, only(RegEx x)方法的文档only(RegEx x)说,这是在生成器生成器的API中的最后选择。

HelloWorld3

生成器的第一个和第二个版本正在处理文本文件,并且不使用我们修改的代码实际上是Java的事实。 生成器的第三个版本将依赖于这一事实,这样就可以创建一个生成器,可以在需要代码生成的类中对其进行配置。

为此,我们可以扩展抽象类AbstractJavaGenerator 。 这个抽象类将找到与源代码相对应的类,并且还将读取该类的注释中编码的配置,如我们所见。 仅当源代码是Java文件,已经编译过的类(抱歉,编译器,我们现在可以修改源代码processEx()processEx()的抽象类实现才调用process(Source source, Class klass, CompoundParams global)可能需要重新编译),并且对该类进行了适当的注释。

生成器代码如下:

package javax0.geci.tutorials.hello;import javax0.geci.api.Source;
import javax0.geci.tools.AbstractJavaGenerator;
import javax0.geci.tools.CompoundParams;import java.io.IOException;public class HelloWorldGenerator3 extends AbstractJavaGenerator {public void process(Source source, Class<?> klass, CompoundParams global)throws IOException {final var segment = source.open(global.get("id"));final var methodName = global.get("methodName", "hello");segment.write_r("public static void %s(){", methodName);segment.write("System.out.println(\"Hello, World\");");segment.write_l("}");}public String mnemonic() {return "HelloWorld3";}
}

方法process() (接口中定义的方法的重载版本)获取三个参数。 第一个是与第一个示例中非常相同的Source对象。 第二个是从我们正在处理的Java源文件创建的Class 。 第三个是框架从类注释读取的配置。 这也需要方法mnemonic()的支持。 这标识了生成器的名称。 它是在配置中用作引用的字符串。 它必须是唯一的。

需要由生成器修改的Java类必须使用Geci注释进行注释。 Geci注释在库javax0.geci.annotations.Geci定义。 用生成的代码扩展的源代码如下所示:

package javax0.geci.tutorials.hello;import javax0.geci.annotations.Geci;@Geci("HelloWorld3 id='hallo' methodName='hiya'")
public class HelloWorld3 {//<editor-fold id="hallo">//</editor-fold>
}

这里有点麻烦。 Java :: Geci是一个测试阶段工具,对其的所有依赖项都是测试依赖项。 注释库是一个例外。 该库必须是常规依赖项,因为使用代码生成的类都带有此注释,因此JVM将在运行时查找该注释类,即使在运行时该注释没有作用。 因为JVM测试执行只是运行时,所以没有区别。

要克服此Java :: Geci,只要注释接口的名称是Geci且它具有一个value (即String ,就可以使用任何注释。 这样,我们可以通过以下方式使用第三个hello world生成器:

package javax0.geci.tutorials.hello;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;@HelloWorld3a.Geci(value = "HelloWorld3 id='hallo'", methodName = "hiyaHuya")
public class HelloWorld3a {//<editor-fold id="hallo">//</editor-fold>@Retention(RetentionPolicy.RUNTIME)@interface Geci {String value();String methodName() default "hello";}
}

请注意,在前面的示例中,参数idmethodName是在value字符串内定义的(如果未在注释中定义任何其他参数,则这是默认参数)。 在这种情况下,很容易将参数拼写错误,并且IDE不会仅仅因为IDE对配置Java :: Geci的字符串格式一无所知就不会为您提供任何支持。 另一方面,如果您有自己的注释,则可以自由定义任何命名参数。 在此示例中,我们在接口中定义了方法methodName 。 Java :: Geci正在读取注释的参数以及解析参数的value字符串。 这样,某些生成器可以使用自己的注释,这些注释可以帮助用户定义定义为注释参数的参数。

我们的第三个“ Hello,World!”的最后一个版本 应用程序可能是最简单的:

package javax0.geci.tutorials.hello;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;public class HelloWorld3b {//<editor-fold id="HelloWorld3" methodName = "hiyaNyunad">//</editor-fold>
}

类上没有注释,也没有看起来像注释的注释。 唯一存在id HelloWorld3editor-fold段是生成器的助记符。 如果存在,则AbstractJavaGenerator意识到这一点并从那里读取参数。 (顺便说一句:即使存在注释,它也会读取注释中不存在的其他参数。)不仅读取参数,还调用具体的实现,因此生成了代码。 这种方法是最简单的,可用于仅需要一个段即可将代码生成到其中的代码生成器,以及当它们不需要类中的方法和字段的单独配置选项时使用。

摘要

在本文中,我描述了如何编写自己的生成器,并且还深入研究了如何使用注释来配置需要生成代码的类。 请注意,本文中讨论的某些功能可能不在发行版中,但是您可以从https://github.com/verhas/javageci下载并构建(b)领先版本。

翻译自: https://www.javacodegeeks.com/2019/05/creating-javageci-generator.html

lemon geci

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓 图像清晰度识别_OCR文字识别的功能及注意事项

首先OCR文字识别是指电子设备检查纸上打印的字符&#xff0c;然后用OCR文字识别技术翻译成计算机文字的过程&#xff1b;就是对文本资料进行扫描&#xff0c;然后对图像文件进行分析处理&#xff0c;获取文字及版面信息的过程。那么在日常生活中有很多公司有文字识别这方面需求…

薪资/薪水/金额的数据类型

MySQL 数据库中&#xff0c;金额字段使用的数据类型和长度建议为&#xff1a;decimal(11,2) 而对应的实体类的成员变量的数据类型建议为&#xff1a;BigDecimal

java中list去除空值_Java –从列表中删除所有空值

java中list去除空值介绍&#xff1a; 在本文中&#xff0c;我们将学习如何使用普通的Java&#xff0c;Java 8 lambda表达式和某些第三方库从Java 列表中删除空值 。 所以&#xff0c;让我们开始吧&#xff01; 从Java中的 让我们探索从Java 列表中删除null的不同方法&#xf…

URI is not registered (Settings | Languages Frameworks | Schemas and DTDs)

参考&#xff1a; https://www.cnblogs.com/ttflove/p/6341469.html https://blog.csdn.net/c_learner_/article/details/107228678

无法识别的属性“targetframework”。请注意属性名称区分大小写。_神奇!你思考过计算机是怎么识别玻璃和透明物体的吗?...

真实场景中的镜面/玻璃检测和语义分割Charmve | English | Chinesehttps://github.com/Charmve/Mirror-Glass-Detection在这个项目中&#xff0c;我正在学习反射镜和玻璃检测/分段技术。镜子是反射表面&#xff0c;可以反射前面的场景&#xff0c;而玻璃是透明表面&#xff0c;…

Java中的out.write()和out.print()的区别

out 就是 PrintWriter 对象。 out.print() 有处理空值&#xff0c;如果传入的字符串为 null&#xff0c;则会转换为"null"字符串&#xff0c;print() 后续还是调用的 write() 方法&#xff0c;write() 传入的字符串不能为空。这个可以通过 PrintWriter 的源码中看到…

python if else用法_python列表推导式中使用if-else

今天在处理自动化邮件数据时碰到数据行中包含字符串后&#xff0c;从hive中拿到的整数型数据自动转化成了浮点数&#xff0c;严重影响美观性。因此想到了用列表推导式来做转化&#xff0c;将其中的数字型数据全部转化为整型&#xff0c;而字符型数据保留原样。 列表推导式总共有…

java使用:: 表达式_Java 12:开关表达式

java使用:: 表达式在Java 12中&#xff0c;对switch语句进行了增强&#xff0c;以便可以将其用作表达式。 现在也可以在一种情况下打开多个常量&#xff0c;从而使代码更简洁易读。 这些增强功能是一种预览语言功能 &#xff0c;这意味着必须使用--enable-preview标志在Java编译…

jsp中request.getAttributeNames()报红

缺少 servlet-api 依赖&#xff1a; <dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency>

fluent瞬态_Java中的瞬态关键字及其使用

fluent瞬态最近&#xff0c;我在一个朋友的一个研究项目中遇到了一个十字架&#xff0c;他们正在学习Java编程的基础知识&#xff0c;其中一些被遗忘的敏感信息打印在文本文件中&#xff0c;并记住了Java中的瞬时关键字。 Java中的瞬时关键字在安全性方面起着重要作用&#xf…

jsp中out.println()报红

需要引入 jsp-api&#xff1a; <dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2.1-b03</version> </dependency>

graphql 有必要吗_您准备好观看GraphQL了吗?

graphql 有必要吗在上一篇文章中&#xff0c;我们讨论了GraphQL与REST相比的优势。 在本文中&#xff0c;我们将看到GraphQL的实际应用。 我创建了一个示例应用程序来展示REST和GraphQL之间的差异。 首先&#xff0c;我们将看到简单产品细节端点的REST实现。 我已经使用Spring …

报错java.lang.NoClassDefFoundError: ognl/DefaultMemberAccess

不要使用新版的 ognl&#xff0c;从 3.2 开始&#xff0c;会报各种乱七八糟的错误。建议使用 3.1.x 版本的&#xff0c;例如下面的版本&#xff1a; <dependency><groupId>ognl</groupId><artifactId>ognl</artifactId><version>3.1.15&l…

spring 注释_Spring核心注释

spring 注释介绍&#xff1a; org.springframework.beans.factory.annotation和org.springframework.context.annotation包中存在的Spring注释通常称为Spring Core注释。 我们可以将它们分为两大类&#xff1a;DI相关的注释和上下文配置注释&#xff1a; 在本教程中&#xff0…

Struts2 <s:debug/> 标签无法显示

首先&#xff0c;确保在 JSP 页面中引入 Struts2 的标签库&#xff1a; <% taglib uri"/struts-tags" prefix"s"%>在 Struts 2 项目中需要查看值栈&#xff08;Value Stack &#xff09;的内容&#xff0c;但是在 JSP 页面中添加了 <s:debug/&g…

JSTL/EL表达式/Struts2标签/OGNL表达式

文章目录JSTL EL表达式Struts 标签 OGNL表达式JSTL EL表达式 JSTL 只能用在 JSP 文件中&#xff0c;不可以在 XML 和 HTML 文件中使用&#xff0c;不可以用在 JS 语境中&#xff0c;不可以用在 Java 的语境中。在 JSP 文件中&#xff0c;JSTL 标签可以使用在 HTML 标签的属…

spring 注释_Spring @Value注释

spring 注释介绍&#xff1a; Spring Value批注用于将值注入变量和方法参数。 我们可以读取spring环境变量或系统变量。 它还支持SpEL。 在本快速教程中&#xff0c;我们将探讨如何使用Spring Value批注。 建立&#xff1a; 让我们首先在app.properties文件中定义一些属性&am…

Struts2标签学习笔记

文章目录Struts2 标签是干什么的Struts2 标签可以使用在哪里关于标签的属性常用的标签s:property调用方法s:iterator遍历Integer类型的Lists:selects:ifs:form自动填写表单项的值s:textfields:includes:submits:checkboxs:radios:action示例代码s:dates:url示例代码s:set示例代…

maven依赖范围_Maven依赖范围

maven依赖范围介绍&#xff1a; 管理依赖关系是Maven的核心功能。 定义Maven依赖项时&#xff0c; scope属性定义了该依赖项在不同的Maven生命周期阶段&#xff08;例如build&#xff0c;test和run&#xff09;上的可见性。 依赖范围限制了任何项目中依赖的传递性&#xff0c;…

雅加达poi_雅加达EE:干净的板岩

雅加达poi该公告雅加达EE不能使用javax。*名称空间是个好消息&#xff0c;并提供雅加达EE用干净的石板上构建和创新企业级Java的未来。 原始提案 可以预见&#xff0c; javax。*和jakarta。*名称空间将在Java EE 8之后共存&#xff0c;随着它的发展&#xff0c; jakarta。*名称…