背景
每個Java開發人員每天都使用某種代碼生成工具。 設置器,獲取器,瑣碎的構造函數,toString –所有這些只是樣板代碼。 通常,我們會在我們最喜歡的IDE的幫助下生成它。 我真的無法想象手動編碼它,并且由于Java是一種靜態語言,我們將永遠無法跳過此過程。
所有現代IDE都提供的那些瑣碎的代碼生成示例并不是唯一有用的代碼生成情況。 有許多現代框架生成一些代碼來幫助我們編寫更可靠的代碼并更快地執行。 我認為最著名的示例是QueryDSL和JPA2元模型生成器 ,它們創建用于執行類型安全的數據庫查詢的對象。
還有其他情況-IDE不能很好地支持-我們可以使用代碼生成。 通常,它可能有助于生成:
- 建造者
- 正面
- 從域對象到DTO的DTO和映射器
這些僅是示例。 對于某些項目,可能存在某些特定于項目的項目,我們不能使用任何現有的代碼生成工具,而必須編寫自己的代碼。 怎么做? 使用Java APT –注釋處理工具 。
關于Java APT的幾句話
Java 1.5中引入了注釋處理工具,它提供了用于處理注釋類的低級API。 它是大多數(也許是全部?)現有代碼生成框架的基礎,并且由于API的級別很低,如果您只想生成一些類,我不建議您使用純Java APT。 使用apt-jelly(另一個代碼生成工具)頁面上的示例 ,可以很清楚地了解使用APT進行代碼生成的情況。
您可以使用現有框架之一,而不必使用普通的Java APT。 最近,我參加了有關有趣的JAnnocessor的會議討論,該JAnnocessor似乎做得很好。
您好JAnnocessor
JAnnocessor是Nikolche Mihajlovski制作的一個相當新的框架。 與APT有何不同? 這是作者怎么說的作者:
JAnnocessor建立在Java APT的基礎上,將Java源代碼模型封裝在豐富而方便的高級域模型中,該模型是表達匹配和轉換的良好目標。
JAnnocessor帶有幾個內置處理器: builder , dto , facade和mapper 。 如果您需要自定義功能,則可以輕松地自己編寫。
有一個很大的缺點–非常差的文檔。 實際上,幾乎沒有任何文檔。 在Wiki中,您找不到太多甚至更糟的東西–在框架類中也找不到Javadocs。 盡管有作者編寫的入門指南 ,但我還是有一些遺漏之處,因此我將逐步指導您完成基礎知識。 ?
Maven設置
我們將僅在編譯階段使用JAnnocessor,因此無需將其添加到我們的應用程序包中-我們將范圍設置為
<dependency><groupId>com.googlecode.jannocessor</groupId><artifactId>jannocessor</artifactId><version>0.7.2</version><scope>provided</scope>
</dependency>
下一部分是注釋處理插件。 盡管《 入門指南》建議使用jannocessor-maven-plugin,但由于缺少一些配置選項,我被迫使用maven-processor-plugin“過時”。
在構建/插件部分,我們添加:
<plugin><groupId>org.bsc.maven</groupId><artifactId>maven-processor-plugin</artifactId><version>2.0.4</version><executions><execution><id>generate-code</id><goals><goal>process</goal></goals><phase>compile</phase><configuration><processors><processor>org.jannocessor.processor.JannocessorProcessor</processor></processors><systemProperties><logback.configurationFile>${project.basedir}/etc/jannocessor-logback.xml</logback.configurationFile></systemProperties><options><templates.path>${project.basedir}/src/main/resources</templates.path></options><defaultOutputDirectory>${project.basedir}/target/generated-sources/</defaultOutputDirectory></configuration></execution></executions>
</plugin>
- 處理器 -告訴maven-processor-plugin哪個類執行注釋處理-請勿更改
- configuration / logback.configurationFile –是可選的。 JAnnocessor使用內部lo??gback進行日志記錄,如果您在項目中也這樣做,并且在classpath中有logback.xml,它將由JAnnocessor使用。 我建議為JAnnocessor編寫單獨的日志記錄配置,以避免可能的問題(例如,如果您使用janino conditionals )。 jannocessor-logback.xml可以很簡單:
<?xml version="1.0" encoding="UTF-8"?> <configuration><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%-30(%date) %-5level %logger{0} %msg%n</pattern></encoder></appender><root level="error"><appender-ref ref="console"/></root></configuration>
- options / templates.path –可能您將使用自定義JAnnocessor模板。 如果您不愿意,可以刪除該行
- defaultOutputDirectory –很重要–默認情況下,將生成的類添加到src / main / java中-在我看來,這是一個非常糟糕的主意。 請記住, 每次Maven構建都會重新創建所有生成的類,并且所有手工修改都將丟失 。 這就是為什么生成的類應該放在
/target/generated-sources/
或/target/generated-test-sources/
建造者一代
在此示例中,我將使用內置生成器為我的簡單POJO生成生成器類。
首先,我們需要新的注釋來標記要為其生成構建器的類。 它可以很簡單:
package pl.maciejwalkowiak.jannocessor.domain;public @interface GenerateBuilder {
}
我們的樣本POJO:
package pl.maciejwalkowiak.jannocessor.domain;@GenerateBuilder
public class Person {private String firstName;private String lastName;private Integer age;public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}
接下來的重要部分是告訴JAnnocessor必須生成什么。 為此,我們需要在特定的包中創建特定的類: org.jannocessor.config.Processors
。 我找不到使它可配置的方法,這樣配置就可以在我們項目的程序包中。
在配置中,我們指定應在何處放置創建的類: pl.maciejwalkowiak.jannocessor.domain.builder
以及基本bean類在哪里: pl.maciejwalkowiak.jannocessor.domain
。 最后一個參數表示我們是否要使用調試模式–目前并不重要。
package org.jannocessor.config;import pl.maciejwalkowiak.jannocessor.domain.GenerateBuilder;import org.jannocessor.extra.processor.BuilderGenerator;
import org.jannocessor.model.structure.JavaClass;
import org.jannocessor.processor.annotation.Annotated;
import org.jannocessor.processor.annotation.Types;public class Processors {@Annotated(GenerateBuilder.class)@Types(JavaClass.class)public BuilderGenerator generateBuilder() {return new BuilderGenerator("pl.maciejwalkowiak.jannocessor.domain.builder", "pl.maciejwalkowiak.jannocessor.domain", false);}
}
運行它
為了運行它,我們只需要執行mvn compile
。 在target/generated-sources/pl/maciejwalkowiak/jannocessor/domain/builder/
我們將找到PersonBuilder
類:
package pl.maciejwalkowiak.jannocessor.domain.builder;import pl.maciejwalkowiak.jannocessor.domain.Person;
import javax.annotation.Generated;/*** Generated by JAnnocessor*/
@Generated("Easily with JAnnocessor")
public class PersonBuilder {private String firstName;private String lastName;private Integer age;public PersonBuilder firstName(String firstName) {this.firstName = firstName;return this;}public PersonBuilder lastName(String lastName) {this.lastName = lastName;return this;}public PersonBuilder age(Integer age) {this.age = age;return this;}public Person build() {Person instance = new Person();instance.setFirstName(firstName);instance.setLastName(lastName);instance.setAge(age);return instance;}}
多虧了builder類,我們有了用于創建Person
對象的流暢接口:
Person person = new PersonBuilder().firstName("John").lastName("Doe").age(25).build();
創建我們自己的發電機
為了創建自定義生成器,JAnnocessor提供了豐富的API和幾個示例。 不幸的是,沒有可用的指南或教程。 對于本文,我想快速編寫FEST Assert 2.x的生成器,但是在研究JAnnocessor源代碼一段時間后,我放棄了。 相反,我將僅展示概念。
為了編寫自定義生成器代碼,您只需要創建從org.jannocessor.extra.processor.AbstractGenerator
繼承的類。
public class MyCustomGenerator extends AbstractGenerator<AbstractJavaClass> {public MyCustomGenerator(String destPackage, boolean inDebugMode) {super(destPackage, inDebugMode);}@Overrideprotected void generateCodeFrom(PowerList<AbstractJavaClass> models, ProcessingContext context) {// ....}
}
PowerList<AbstractJavaClass> models
表示所有帶有自定義注釋的類的集合。 然后,您可以訪問所有類的字段,方法,已實現的接口等。我唯一想念的就是對類超類的豐富訪問。 為了獲得超類的字段,我不得不使用Java Reflection API。
如果您想編寫自定義生成器,我鼓勵您看一下諸如BuilderGenerator之類的示例 。 數量不多,但絕對有幫助。 ?
摘要
在這篇文章中,我展示了如何設置和使用JAnnocessor。 盡管我認為它很好而且可能非常有用的庫,但是缺少文檔使其無法在真正的嚴肅項目中使用。 我希望Nikolche能夠撰寫出色的文檔或圍繞將要實現的項目建立社區。 我也希望該項目將移至github。 它以某種方式成為標準,因此如果作者希望圍繞它建立社區–我認為這是唯一正確的舉動。 盡管如此,我還是問了他這個問題,至少到目前為止,他沒有任何計劃。
參考: Software Development Journey博客上的JCG合作伙伴 Maciej Walkowiak 使用JAnnocessor進行Java代碼生成 。
翻譯自: https://www.javacodegeeks.com/2012/08/java-code-generation-with-jannocessor.html