plenty of features 已经在 Jeta
上可用,但是如果缺少某些东西怎么办。我可以创建自己的注释并为它们生成元代码吗?
需要一个如何创建自定义 Jeta
处理器的分步教程。
最佳答案
如何创建自定义处理器,分步教程
第 1 步:Hello, World
项目
在本教程中,让我们创建一个简单的 Gradle
项目,其中包含一个模块 app
和一个类 SayHelloApp
。此类将 Hello, World!
写入标准输出。
对于插图,我们将创建 Hello
注释,将 Hello, Jeta!
字符串设置为注释字段。
第 2 步:common
模块
首先,我们需要一个可以在 app
和 apt
(即将创建)模块中访问的模块。在 common
模块中,我们需要两个类 - Hello
注释和 HelloMetacode
接口(interface):
第 3 步:apt
模块apt
- 是一个模块,我们将在其中创建代码生成类所需的所有内容。对于本教程,我们需要一个处理器来处理我们的 Hello
注释。
请注意,此模块依赖于 common
模块,因此我们使用 Hello
注释作为 super 构造函数的参数。通过这样做,我们对 Jeta
说我们需要使用给定类型注释的所有元素。该模块还依赖于 jeta-apt
以访问 Jeta
类。
第 4 步:处理器
创建的 SayHelloProcessor
现在什么也不做。让我们在其中添加一些逻辑。这里的想法是生成 java 代码,将 Hello, Jeta
字符串设置为用 Hello
注释的字段。
注意 Jeta
使用 JavaPoet
创建 java 源代码。 Square
确实是一个很棒的框架。请在 GitHub 上查看。
首先,我们需要 metacode 实现 HelloMetacode
。为此,我们将向 builder
添加 super 接口(interface):
MetacodeContext context = roundContext.metacodeContext();
ClassName masterClassName = ClassName.get(context.masterElement());
builder.addSuperinterface(ParameterizedTypeName.get(
ClassName.get(HelloMetacode.class), masterClassName));
接下来,通过创建
HelloMetacode
方法来实现 void setHello(M master)
:MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("setHello")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(masterClassName, "master");
最后,用
Hello
注释的每个元素的语句,Jeta
通过 process
参数传入 roundContext
方法:for (Element element : roundContext.elements()) {
String fieldName = element.getSimpleName().toString();
methodBuilder.addStatement("master.$L = \"Hello, Jeta\"", fieldName);
}
这是完整的
SayHelloProcessor
list :package org.brooth.jeta.samples.apt;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import org.brooth.jeta.apt.MetacodeContext;
import org.brooth.jeta.apt.RoundContext;
import org.brooth.jeta.apt.processors.AbstractProcessor;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
public class SayHelloProcessor extends AbstractProcessor {
public SayHelloProcessor() {
super(Hello.class);
}
@Override
public boolean process(TypeSpec.Builder builder, RoundContext roundContext) {
MetacodeContext context = roundContext.metacodeContext();
ClassName masterClassName = ClassName.get(context.masterElement());
builder.addSuperinterface(ParameterizedTypeName.get(
ClassName.get(HelloMetacode.class), masterClassName));
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("setHello")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(masterClassName, "master");
for (Element element : roundContext.elements()) {
String fieldName = element.getSimpleName().toString();
methodBuilder.addStatement("master.$L = \"Hello, Jeta\"", fieldName);
}
builder.addMethod(methodBuilder.build());
return false;
}
}
第 5 步:元代码
代码生成类所需的所有内容都已创建,我们准备好尝试了。但首先,我们需要添加
jeta.properties
文件以配置 Jeta
。您可以在 on this page 中找到有关此文件的更多详细信息。该文件应位于根包中。对于我们的教程,它的内容是:metasitory.package=org.brooth.jeta.samples
processors.add=org.brooth.jeta.samples.apt.SayHelloProcessor
接下来,修改
SayHelloApp
。我们将在其上放置 text
注释,而不是初始化 Hello
字段:public class SayHelloApp {
@Hello
String text;
}
和
build.gradle
:group 'org.brooth.jeta-samples'
version '1.0'
buildscript {
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath 'net.ltgt.gradle:gradle-apt-plugin:0.5'
}
}
apply plugin: 'net.ltgt.apt'
apply plugin: 'java'
sourceCompatibility = 1.7
repositories {
mavenCentral()
jcenter()
}
compileJava {
options.sourcepath = files('src/main/java')
}
dependencies {
apt project(':apt')
compile project(':common')
compile 'org.brooth.jeta:jeta:+'
}
现在我们已准备好生成元代码。在控制台中运行下一个命令:
./gradlew assemble
如果到目前为止没有问题,我们将在
SayHelloApp_Metacode
目录下看到 app/build
文件:第 6 步: Controller
Controllers 是将元代码应用于 masters 的类。让我们在
HelloMetacode
模块中为 app
创建一个: package org.brooth.jeta.samples;
import org.brooth.jeta.MasterController;
import org.brooth.jeta.metasitory.Metasitory;
public class SayHelloController<M> extends MasterController<M, HelloMetacode<M>> {
public SayHelloController(Metasitory metasitory, M master) {
super(metasitory, master, Hello.class, false);
}
public void setHello() {
for (HelloMetacode<M> metacode : metacodes)
metacode.setHello(master);
}
}
第 7 步:MetaHelper
MetaHelper
是一个简单的静态助手类。如果您对静态助手不满意,则不应在您的项目中使用它。您可以在 this page 上阅读有关此类的更多详细信息。无论如何,让我们在
MetaHelper
模块中创建 app
:package org.brooth.jeta.samples;
import org.brooth.jeta.metasitory.MapMetasitory;
import org.brooth.jeta.metasitory.Metasitory;
public class MetaHelper {
private static MetaHelper instance;
private final Metasitory metasitory;
public static MetaHelper getInstance() {
if (instance == null)
instance = new MetaHelper("org.brooth.jeta.samples");
return instance;
}
private MetaHelper(String metaPackage) {
metasitory = new MapMetasitory(metaPackage);
}
public static void setHello(Object master) {
new SayHelloController<>(getInstance().metasitory, master).setHello();
}
}
请注意,我们必须将在
MapMetasitory
中指定为 "org.brooth.jeta.samples"
的相同包 (metasitory.package
) 传递给 jeta.properties
。第 8 步:使用
最后一步 - 我们调用
MetaHelper
的方法。这是 SayHelloApp
的完整列表:package org.brooth.jeta.samples;
public class SayHelloApp {
@Hello
String text;
public SayHelloApp() {
MetaHelper.setHello(this);
}
public void sayHello() {
System.out.print(text);
}
public static void main(String[] args) {
new SayHelloApp().sayHello();
}
}
最后,我们可以运行
SayHelloApp
。在控制台中,我们应该看到:Hello, Jeta
链接
快乐的代码生成! :)