Jeta:如何创建自定义注释处理器

时间:2016-05-13 12:29:41

标签: java android annotation-processing jeta androjeta

Jeta上已有plenty of features,但如果缺少某些内容,该怎么办?我可以创建自己的注释并为它们生成元代码吗?

如何创建自定义Jeta处理器需要一步一步的教程。

1 个答案:

答案 0 :(得分:11)

如何创建自定义处理器,分步教程

第1步:Hello, World项目

在本教程中,让我们创建一个简单的Gradle项目,其中包含一个模块app和一个类SayHelloApp。该类将Hello, World!写入标准输出。

SayHelloApp

为了说明,我们将创建Hello注释,将Hello, Jeta!字符串设置为带注释的字段。

第2步:common模块

首先,我们需要一个可在appapt(即将创建)模块中访问的模块。在common模块中,我们需要两个类 - Hello注释和HelloMetacode接口:

common module

第3步:apt模块

apt - 是一个模块,我们将在其中创建代码生成类所需的所有内容。在本教程中,我们需要一个处理器来处理Hello注释。

apt module

请注意,此模块依赖于common模块,因此我们使用Hello注释作为超级构造函数的参数。通过这样做,我们向Jeta说我们需要所有使用给定类型注释的元素。该模块还依赖jeta-apt来访问Jeta类。

第4步:处理器

创建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;
    }
}

步骤5:Metacode

创建了代码生成类所需的所有内容,我们已准备好尝试。但首先,我们需要添加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文件:

SayHelloApp_Metacode

第6步:控制器

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

链接

快乐的代码生成! :)