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

时间:2013-02-12 07:32:41

标签: java annotations apt java-compiler-api

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

  • 源文件使用方法
  • 上的自定义注释编写
  • 方法主体需要根据注释稍加变化。
  • 不应更改源文件,但应修改输入到编译器源文件

我看过下面的API -

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

我想通过以下方式设计:

  1. 编写注释处理器
  2. 生成编译器树
  3. 在运行时编辑编译器树而不影响原始源文件
  4. 将树提供给编译器
  5. 编译器树API似乎在它允许访问的位置 com.sun.source.tree.MethodTree

    但是,编译器树API似乎是只读的。 我无法弄清楚如何完成步骤3& 4

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

    注意:我正在寻找唯一的源代码操作技术。没有运行时字节代码操作/ AOP

    环境:Java 6

3 个答案:

答案 0 :(得分:3)

你可以用下面的东西来完成3)和4)。

取自java annotation processor example

的示例
@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;
  }
}

使用projectlombok和自定义处理程序的另一种方式。

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代码。

答案 1 :(得分:2)

标准注释处理API 支持直接修改源代码。但是,通过生成带注释类型的超类或子类,可以获得修改源代码的一些效果。下面的博客条目显示了这种技术的一个例子:

"Properties via Annotation Processing"

答案 2 :(得分:0)

我建议你将所有源代码复制到一个单独的目录,修改那里的代码并从临时路径构建。