使用源代码操作进行 Java 注释处理

2022-09-03 07:57:58

我一直在为以下要求寻找解决方案 -

  • 源文件使用方法上的自定义批注编写
  • 方法主体需要基于注释进行一些更改。
  • 源文件不应更改,但编译器的输入应修改源文件

我已经看了下面的API -

  • javax.annotation.processing - Annotation processing.
  • javax.lang.model.* - 用于注释处理和编译器树 API 的语言模型
  • com.sun.source.* - Compiler Tree API.

我想通过以下方式设计这个:

  1. 编写注释处理器
  2. 生成编译器树
  3. 在运行时编辑编译器树,而不会影响原始源文件
  4. 将树提供给编译器

Compiler Tree API似乎正在承诺它允许访问com.sun.source.tree.MethodTree。

但是,编译器树 API 似乎是只读的。我不知道如何完成步骤3和4

是否有任何API可供我采用来完成任务

注意:我只在寻找源代码操作技术。无运行时字节代码操作/ AOP

环境:Java 6


答案 1

标准注释处理 API 不支持直接修改源代码。但是,修改源代码的某些效果可以通过生成带注释类型的超类或子类来实现。下面的博客文章显示了此技术的示例:

“通过注释处理实现属性”


答案 2

您可以在下面执行此操作,这将使您完成3)和4)。

示例取自 Java 注释处理器示例

@SupportedAnnotationTypes( "com.javacodegeeks.advanced.processor.Immutable" )
@SupportedSourceVersion( SourceVersion.RELEASE_7 )
public class SimpleAnnotationProcessor extends AbstractProcessor {
  @Override
  public boolean process(final Set< ? extends TypeElement > annotations, 
      final RoundEnvironment roundEnv) {

    for( final Element element: roundEnv.getElementsAnnotatedWith( Immutable.class ) ) {
      if( element instanceof TypeElement ) {
        final TypeElement typeElement = ( TypeElement )element;

        for( final Element eclosedElement: typeElement.getEnclosedElements() ) {
       if( eclosedElement instanceof VariableElement ) {
           final VariableElement variableElement = ( VariableElement )eclosedElement;

           if( !variableElement.getModifiers().contains( Modifier.FINAL ) ) {
             processingEnv.getMessager().printMessage( Diagnostic.Kind.ERROR,
               String.format( "Class '%s' is annotated as @Immutable, 
                 but field '%s' is not declared as final", 
                 typeElement.getSimpleName(), variableElement.getSimpleName()            
               ) 
             );                     
           }
         }
       }
    }

    // Claiming that annotations have been processed by this processor 
    return true;
  }
}

使用具有自定义处理程序的投影龙目的另一种方法。

GitHub Project Lombok 内置的处理程序示例。此注释添加了 try catch 块

public class SneakyThrowsExample implements Runnable {
    @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }

    @SneakyThrows
    public void run() {
        throw new Throwable();
    }
}

这将被处理为

public String utf8ToString(byte[] bytes) {
    try {
        return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw Lombok.sneakyThrow(e);
    }
}

public void run() {
    try {
        throw new Throwable();
    } catch (Throwable t) {
        throw Lombok.sneakyThrow(t);
    }
}

您可以在同一个Github/lombok网站上找到Handler代码。


推荐