15

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

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

我查看了以下 API -

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

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

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

编译器树 API 似乎很有希望,它可以访问 com.sun.source.tree.MethodTree

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

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

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

环境:Java 6

4

3 回答 3

3

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

“通过注释处理的属性”

于 2013-02-18T19:13:41.630 回答
3

您可以按照以下方式执行此操作,这将使您完成 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;
  }
}

另一种使用带有自定义处理程序的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 站点上找到处理程序代码。

于 2014-09-26T18:58:25.303 回答
0

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

于 2013-02-18T19:23:11.523 回答