牛商网做网站的思路,广告联盟评测,简述dw网站开发流程,中国建筑招聘官网2022lemon geci几天前#xff0c;我写了有关Java :: Geci架构#xff0c;代码生成原理以及生成Java源代码的可能不同方式的文章。 在本文中#xff0c;我将讨论在Java :: Geci中创建生成器有多么简单。 您好#xff0c;Wold生成器 HelloWorld1 最简单的生成器是Hello, World… 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 idhello///editor-fold 在源代码中。 segment对象可用于将行写入代码。 write()方法write()一行。 方法write_r()也会写一行但是它也表示必须缩进该行之后的行。 相反的是write_l() 该信号指示已经将此行和连续的行重新制表回到先前的位置。 要使用生成器我们应该有一个需要它的类。 这是 package javax0.geci.tutorials.hello;public class HelloWorld1 {//editor-fold idhello///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 {TestDisplayName(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 idhellopublic 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 {TestDisplayName(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 idhallo methodNamehiya)
public class HelloWorld3 {//editor-fold idhallo///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 idhallo, methodName hiyaHuya)
public class HelloWorld3a {//editor-fold idhallo///editor-foldRetention(RetentionPolicy.RUNTIME)interface Geci {String value();String methodName() default hello;}
} 请注意在前面的示例中参数id和methodName是在value字符串内定义的如果未在注释中定义任何其他参数则这是默认参数。 在这种情况下很容易将参数拼写错误并且IDE不会仅仅因为IDE对配置Java :: Geci的字符串格式一无所知就不会为您提供任何支持。 另一方面如果您有自己的注释则可以自由定义任何命名参数。 在此示例中我们在接口中定义了方法methodName 。 Java :: Geci正在读取注释的参数以及解析参数的value字符串。 这样某些生成器可以使用自己的注释这些注释可以帮助用户定义定义为注释参数的参数。 我们的第三个“ HelloWorld”的最后一个版本 应用程序可能是最简单的 package javax0.geci.tutorials.hello;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;public class HelloWorld3b {//editor-fold idHelloWorld3 methodName hiyaNyunad///editor-fold
} 类上没有注释也没有看起来像注释的注释。 唯一存在id HelloWorld3的editor-fold段是生成器的助记符。 如果存在则AbstractJavaGenerator意识到这一点并从那里读取参数。 顺便说一句即使存在注释它也会读取注释中不存在的其他参数。不仅读取参数还调用具体的实现因此生成了代码。 这种方法是最简单的可用于仅需要一个段即可将代码生成到其中的代码生成器以及当它们不需要类中的方法和字段的单独配置选项时使用。 摘要 在本文中我描述了如何编写自己的生成器并且还深入研究了如何使用注释来配置需要生成代码的类。 请注意本文中讨论的某些功能可能不在发行版中但是您可以从https://github.com/verhas/javageci下载并构建b领先版本。 翻译自: https://www.javacodegeeks.com/2019/05/creating-javageci-generator.htmllemon geci