日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

创建一个Java :: Geci生成器

發(fā)布時(shí)間:2023/12/3 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 创建一个Java :: Geci生成器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

幾天前,我寫了有關(guān)Java :: Geci架構(gòu),代碼生成原理以及生成Java源代碼的可能不同方式的文章。

在本文中,我將討論在Java :: Geci中創(chuàng)建生成器有多么簡單。

您好,Wold生成器

HelloWorld1

最簡單的生成器是Hello, World! 發(fā)電機(jī)。 這將生成一個(gè)打印Hello, World!的方法Hello, World! 到標(biāo)準(zhǔn)輸出。 要?jiǎng)?chuàng)建此生成器,Java類必須實(shí)現(xiàn)Generator接口。 生成器的整個(gè)代碼為:

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);}} }

這確實(shí)是整個(gè)生成器類。 沒有簡化或刪除的行。 當(dāng)框架找到需要方法hello()的文件時(shí),它將調(diào)用process() 。

方法process ()查詢名為“ hello”的段。 這是指線

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

在源代碼中。 segment對象可用于將行寫入代碼。 write()方法write()一行。 方法write_r()也會(huì)寫一行,但是它也表示必須縮進(jìn)該行之后的行。 相反的是write_l() ,該信號(hào)指示已經(jīng)將此行和連續(xù)的行重新制表回到先前的位置。

要使用生成器,我們應(yīng)該有一個(gè)需要它的類。 這是

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

我們還需要一個(gè)測試,該測試將在每次編譯代碼并運(yùn)行單元測試時(shí)運(yùn)行代碼生成:

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);} }

執(zhí)行代碼后,將修改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> }

這是一個(gè)非常簡單的示例,我們可以進(jìn)一步發(fā)展。

HelloWorld2

該示例中低于標(biāo)準(zhǔn)的一件事是,生成器的范圍在調(diào)用only()方法的測試中受到限制。 更好的做法是讓框架掃描所有文件并選擇本身以某種方式表明它們需要生成器服務(wù)的源文件。 在“你好,世界!”的情況下 生成器,它可以是hello段的存在,作為源代碼中的編輯器折疊。 如果存在,則代碼需要方法hello() ,否則不需要。 我們可以通過這種方式實(shí)現(xiàn)生成器的第二個(gè)版本。 我們還修改了實(shí)現(xiàn),而不僅是實(shí)現(xiàn)接口Generator還擴(kuò)展了抽象類AbstractGeneratorEx 。 名稱中的后綴Ex表示該類為我們處理異常。 這個(gè)抽象類實(shí)現(xiàn)方法process()并調(diào)用要定義的processEx() ,該簽名具有與process()相同的簽名,但允許拋出異常。 如果發(fā)生這種情況,則將其封裝在GeciException ,就像我們在第一個(gè)示例中所做的那樣。

該代碼將如下所示:

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("}");}} }

盡管它正在檢查段的存在,但它甚至比第一個(gè)簡單。 當(dāng)代碼調(diào)用source.open("hello") ,如果源代碼中沒有名為hello段,則該方法將返回null 。 使用第二個(gè)生成器的實(shí)際代碼與第一個(gè)相同。 當(dāng)我們在代碼庫中運(yùn)行兩個(gè)測試時(shí),它們都會(huì)生成代碼,所幸的是相同的。

調(diào)用第二個(gè)生成器的測試是

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);} }

請注意,這一次我們不需要限制調(diào)用only()方法的代碼掃描。 同樣, only(RegEx x)方法的文檔only(RegEx x)說,這是在生成器生成器的API中的最后選擇。

HelloWorld3

生成器的第一個(gè)版本和第二個(gè)版本正在處理文本文件,并且不使用我們修改的代碼實(shí)際上是Java的事實(shí)。 生成器的第三個(gè)版本將依賴于這一事實(shí),這樣就可以創(chuàng)建一個(gè)生成器,可以在需要代碼生成的類中對其進(jìn)行配置。

為此,我們可以擴(kuò)展抽象類AbstractJavaGenerator 。 這個(gè)抽象類將找到與源代碼相對應(yīng)的類,并且還將讀取該類的注釋中編碼的配置,我們將看到。 僅當(dāng)源代碼是Java文件,已經(jīng)編譯過的類(抱歉,編譯器,我們現(xiàn)在可以修改源代碼processEx() , processEx()的抽象類實(shí)現(xiàn)才調(diào)用process(Source source, Class klass, CompoundParams global)可能需要重新編譯),并且對該類進(jìn)行了適當(dāng)?shù)淖⑨尅?

生成器代碼如下:

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() (接口中定義的方法的重載版本)獲取三個(gè)參數(shù)。 第一個(gè)是與第一個(gè)示例中非常相同的Source對象。 第二個(gè)是從我們正在處理的Java源文件創(chuàng)建的Class 。 第三個(gè)是框架從類注釋讀取的配置。 這也需要方法mnemonic()的支持。 這標(biāo)識(shí)了生成器的名稱。 它是在配置中用作引用的字符串。 它必須是唯一的。

需要使用生成器進(jìn)行修改的Java類必須使用Geci注釋進(jìn)行注釋。 Geci注釋在庫javax0.geci.annotations.Geci定義。 用生成的代碼擴(kuò)展的源代碼將如下所示:

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> }

這里有點(diǎn)麻煩。 Java :: Geci是一個(gè)測試階段工具,對其的所有依賴項(xiàng)都是測試依賴項(xiàng)。 注釋庫是一個(gè)例外。 該庫必須是正常的依賴項(xiàng),因?yàn)槭褂么a生成的類都帶有此注釋,因此JVM將在運(yùn)行時(shí)查找該注釋類,即使在運(yùn)行時(shí)該注釋沒有作用。 因?yàn)镴VM測試執(zhí)行只是運(yùn)行時(shí),所以沒有區(qū)別。

要克服此Java :: Geci,您可以使用任何注釋,只要注釋接口的名稱為Geci且其value是String 。 這樣,我們可以通過以下方式使用第三個(gè)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";} }

請注意,在前面的示例中,參數(shù)id和methodName是在value字符串內(nèi)定義的(如果未在注釋中定義任何其他參數(shù),則這是默認(rèn)參數(shù))。 在這種情況下,很容易將參數(shù)拼寫錯(cuò)誤,并且IDE不會(huì)僅僅因?yàn)镮DE對配置Java :: Geci的字符串格式一無所知就不會(huì)為您提供任何支持。 另一方面,如果您有自己的注釋,則可以自由定義任何命名參數(shù)。 在此示例中,我們在接口中定義了方法methodName 。 Java :: Geci正在讀取注釋的參數(shù)以及解析參數(shù)的value字符串。 這樣,某些生成器可以使用自己的注釋,這些注釋可以幫助用戶定義定義為注釋參數(shù)的參數(shù)。

我們的第三個(gè)“ Hello,World!”的最后一個(gè)版本 應(yīng)用程序可能是最簡單的:

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 HelloWorld3的editor-fold段是生成器的助記符。 如果存在,則AbstractJavaGenerator意識(shí)到這一點(diǎn)并從那里讀取參數(shù)。 (順便說一句:即使存在注釋,它也會(huì)讀取注釋中不存在的其他參數(shù)。)不僅讀取參數(shù),還調(diào)用具體的實(shí)現(xiàn),因此生成了代碼。 這種方法最簡單,可用于僅需要一個(gè)段即可將代碼生成到其中的代碼生成器,以及當(dāng)它們不需要類中方法和字段的單獨(dú)配置選項(xiàng)時(shí)使用。

摘要

在本文中,我描述了如何編寫自己的生成器,并且還深入研究了如何使用注釋來配置需要生成代碼的類。 請注意,本文中討論的某些功能可能不在發(fā)行版中,但是您可以從https://github.com/verhas/javageci下載并構(gòu)建(b)領(lǐng)先版本。

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

總結(jié)

以上是生活随笔為你收集整理的创建一个Java :: Geci生成器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。