Jeta
上已有plenty of features,但如果缺少某些内容,该怎么办?我可以创建自己的注释并为它们生成元代码吗?
如何创建自定义Jeta
处理器需要一步一步的教程。
答案 0 :(得分:11)
Hello, World
项目在本教程中,让我们创建一个简单的Gradle
项目,其中包含一个模块app
和一个类SayHelloApp
。该类将Hello, World!
写入标准输出。
为了说明,我们将创建Hello
注释,将Hello, Jeta!
字符串设置为带注释的字段。
common
模块首先,我们需要一个可在app
和apt
(即将创建)模块中访问的模块。在common
模块中,我们需要两个类 - Hello
注释和HelloMetacode
接口:
apt
模块 apt
- 是一个模块,我们将在其中创建代码生成类所需的所有内容。在本教程中,我们需要一个处理器来处理Hello
注释。
请注意,此模块依赖于common
模块,因此我们使用Hello
注释作为超级构造函数的参数。通过这样做,我们向Jeta
说我们需要所有使用给定类型注释的元素。该模块还依赖jeta-apt
来访问Jeta
类。
创建SayHelloProcessor
现在什么也没做。让我们在其中添加一些逻辑。这里的想法是生成java代码,将Hello, Jeta
字符串设置为用Hello
注释的字段。
请注意Jeta
使用JavaPoet
来创建java源代码。它是Square
真正伟大的框架。请在GitHub上查看。
首先,我们需要metacode实现HelloMetacode
。为此,我们将超级界面添加到builder
:
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
列表:
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;
}
}
创建了代码生成类所需的所有内容,我们已准备好尝试。但首先,我们需要添加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
文件:
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);
}
}
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
。
最后一步 - 我们调用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
快乐的代码生成! :)