plenty of features 已经在 Jeta 上可用,但是如果缺少某些东西怎么办。我可以创建自己的注释并为它们生成元代码吗?

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

最佳答案

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

第 1 步:Hello, World 项目

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

对于插图,我们将创建 Hello 注释,将 Hello, Jeta! 字符串设置为注释字段。

第 2 步:common 模块

首先,我们需要一个可以在 appapt(即将创建)模块中访问的模块。在 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

链接
  • 本教程介绍 GitHub
  • Jeta Website
  • Jeta on Android

  • 快乐的代码生成! :)

    10-06 01:21