创建一个Java :: 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且其valueString 。 这样,我们可以通过以下方式使用第三个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

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

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

相关文章

物联网技术的应用和发展

和数字城市、无线城市、智能城市这些理念不同&#xff0c;智慧城市是源于2010年。它是建立在云计算和物联网技术等技术的蓬勃发展的基础上&#xff0c;并与政府行业的需求相结合而产生的。 所以&#xff0c;智慧城市并没有一个特定的标准&#xff0c;智慧城市也难以一蹴而就&am…

c语言 将点同时保证x坐标从小到大,y坐标从小到大地排序,C语言第五六次作业.ppt...

《C语言第五六次作业.ppt》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《C语言第五六次作业.ppt(40页珍藏版)》请在人人文库网上搜索。1、C语言作业解析,第四弹,。原来真正变态的是这两作业哇 原本是做完第五次作业等大家数分期中考完以后给大家&#xff0c;结果直接…

物联网应用技术的十大基础功能

物联网应用技术是基于互联网的基础&#xff0c;在互联网发展到一定的程度后&#xff0c;物联网应用技术也就应运而生。众所周知&#xff0c;物联网最基本的功能特征就是“无处不在的链接和在线服务”&#xff0c;此外还具备以下十大基本功能&#xff1a; 1、定位追溯&#xff1…

光端机与光电转换器的区别介绍

光端机与光电转换器从本质上讲没啥明百显的界限或区别&#xff0c;都是把光信号和电信号之间做个转换度。实际使用上&#xff1a;光电转换器&#xff08;知俗称‘收发器’&#xff09;&#xff0c;一般用道来传输数据信号&#xff1b;而光端机一般指的都内是视频光端容机&#…

物联网在智慧林业中的应用

以森林防火视频监控、道路视频监控、红外野保相机、生态因子监测、水文水质监测、无线通信专网等物联网相关技术在林业科研、生产、管理及服务上都得到了非常广泛的应用&#xff0c;并且已经成为了支撑智慧林业发展的只要信息手段。 智慧林业具有感知化、物联化、智能化、生态化…

红心大战c语言程序设计教程课后答案,[原创]Windows 红心大战随机发牌程序分析...

[调试逆向][原创]Windows 红心大战随机发牌程序分析2007-11-27 23:2813191[调试逆向][原创]Windows 红心大战随机发牌程序分析2007-11-27 23:2813191Windows 红心大战有52张牌&#xff0c;每次开局时&#xff0c;程序会自动洗牌和发牌。按照我们一般的想法&#xff0c;随机发牌…

物联网无线传输技术有哪些?

随着万物互联的时代到来&#xff0c;物体与物体之间的链接方式也在随着时代不断的发展。如果说传感器是物联网的触觉&#xff0c;那么无线传输技术就是物联网的神经系统&#xff0c;将遍布在物联网各处的传感器链接起来。在物联网出现之前&#xff0c;网络的接入需求主要集中在…

武警五防一体化是什么?五防光端机产品介绍!

五防功能是指&#xff1a;&#xff08;1&#xff09;防止误分、抄合断路器。&#xff08;2&#xff09;防止带负荷分、合隔离开关。&#xff08;3&#xff09;防止带电挂&#xff08;合&#xff09;接地线&#xff08;接地刀闸&#xff09;。 &#xff08;4&#xff09;防止带接…

物联网对石油燃气行业的作用

在石油和天然气行业中&#xff0c;应为物联网的特性&#xff0c;能达到很多人工难以达到的效果&#xff0c;让企业更高效方便的开展日常的运营监察工作。 下面就是物联网在油气行业中的真实应用场景&#xff1a; 钻井管理 钻井是油气行业重要的基础组成部分。物联网就能显著的提…

java教程java自学_15必须阅读Java 8教程

java教程java自学Java 8于上个月发布&#xff0c;并且充满了新功能和幕后优化。 互联网在覆盖所有这些新增功能&#xff08;包括好与坏&#xff09;方面都做得相当不错 。 我认为最好汇总一下我们认为是其中最好的一些教程&#xff0c;以帮助您快速掌握最新知识和需要了解的知识…

简要分析光端机选购必备条件

目前&#xff0c;市场上出现很多假冒伪劣的光端机&#xff0c;为了让安防用户或消费者能够更清楚地了解光端机从生产到出厂的过程&#xff0c;我们一同关注从生产加工到出厂&#xff0c;光端机如何挑战三重质检&#xff0c;最终的合格产品。安防产品不同于不同的消费品&#xf…

C语言结构体通过 scanf初始化,C语言结构体数组内带字符数组初始化和赋值

1.首先定义结构体数组&#xff1a;typedef struct BleAndTspRmtCmd{char terminal[3];char note[3];char rmtCmd[10];char cmdPropt[24];};BleAndTspRmtCmd为结构体名&#xff0c;可以通过这个结构体名定义其他结构体变量&#xff0c;struct BleAndTspRmtCmd variable&#xff…

zigbee智能家居

近几年来&#xff0c;智能家居设备的增长速度是极快的。曾经也被称作家庭自动化&#xff0c;和现在的“物联网”&#xff0c;已经转化为我们更加方便理解的类型了&#xff0c;我们统称为智能家居。现在不断出现的暖气、照明、摄像头、和传感器以及现在不断出现的新设备&#xf…

物联网和互联网的区别

互联网开始于1969年美国的阿帕网。是网络与网络之间做成的一种网络形式。这些网络通过一组通用的协议连接&#xff0c;形成一个巨大的国际性网络。通常interne就是泛指互联网&#xff0c;而Internet则指的是因特网。这种将计算机网络相互链接在一起的方式就称作“网络互联”&am…

JMetro版本5.3已发布

JMetro的另一个版本刚刚发布。 这次是5.3版。 在此版本中&#xff0c;为尚未使用的控件添加了一些新样式。 还调整了一些较旧的样式&#xff0c;并修复了一些错误。 我还将展示一些使用JMetro的大公司。 诸如Google&#xff0c;Amazon等的名称。 以下是添加的样式&#xff1a…

c语言文件指针ab命令,C语言试题,~库(完整版~).doc

-_C语言试题库单项选择C语言概述一个C程序的执行是从A、本程序的MAIN函数开始&#xff0c;到MAIN 函数结束。B、本程序文件的第一个函数开始&#xff0c;到本程序文件的最后一个函数结束。C、本程序的MAIN函数开始&#xff0c;到本程序的最后一个函数结束。D、本程序文件的第一…

电话光端机安装的方法,电话光端机设备安装注意事项

电话光端机就是把传统的电话信号转换成光信号并在光纤上传输的设备&#xff0c;其设备内置精密器件&#xff0c;请注意轻拿轻放&#xff0c;避免剧烈震动&#xff0c;以免影响设备性能。如果您发现设备在运输过程中被损坏或丢失了任何部件&#xff0c;请通知飞畅科技售后服务部…

“智慧灯杆”的应用和解决方案

路灯是我们照亮城市的基础应用&#xff0c;遍布在我们城市的每个角落。应用我们新的物联网、云计算等技术&#xff0c;可以形成一个“路联网”系统。通过整合所有的路灯&#xff0c;将传感设备安装到路灯上&#xff0c;这就构成了我们新型城市的网络基础——“智慧路灯”。 物…

小白也能轻松看懂的lora物联网!

什么物联网场景用LoRa&#xff1f; 在偏远地区&#xff0c;如果没有NB-IoT信号&#xff0c;那么就更适合用LORA了。例如高原地区的牛羊定位管理&#xff0c;养牦牛的或者是养跑山猪的。或者是物联网设备很密集的地方&#xff0c;LORA也会比NB更便宜。例如智慧小区、智慧园区等等…

java字符串加入空格_Java终于可以加入字符串

java字符串加入空格我确定您处于想要连接多个字符串的情况。 如果您使用的不是Java编程语言&#xff0c;则可能使用了该编程语言提供的join&#xff08;&#xff09;函数。 如果使用Java&#xff0c;则无法执行此操作。 没有join&#xff08;&#xff09;方法。 Java标准类库为…