【问题标题】:Java annotation processing with source code manipulation带有源代码操作的 Java 注释处理
【发布时间】:2013-01-27 11:11:42
【问题描述】:

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

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

我查看了以下 API -

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

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

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

Compiler Tree API 似乎很有希望它可以访问 com.sun.source.tree.MethodTree

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

有没有我可以采用的 API 来完成任务

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

环境:Java 6

【问题讨论】:

  • This annotation library 通过根据上面的注释初始化字符串字段的值来修改源代码。也许你可以用它作为例子。

标签: java annotations apt java-compiler-api


【解决方案1】:

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

"Properties via Annotation Processing"

【讨论】:

    【解决方案2】:

    您可以按照下面的方式执行此操作,这将使您完成 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 站点上找到处理程序代码。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-03
        • 2011-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-09
        • 2017-05-22
        相关资源
        最近更新 更多