【问题标题】:Java 6 - Annotation processor and code additionJava 6 - 注释处理器和代码添加
【发布时间】:2011-04-14 04:06:13
【问题描述】:

我编写了一个自定义注释,其中包含属性的元数据和AnnotationProcessor

@SupportedAnnotationTypes({"<package>.Property"})
public class PropertyProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        // Get messager object
        Messager messager = processingEnv.getMessager();
        // Iterate through the annotations
        for(TypeElement typeElement : annotations) {
            // Iterate through the annotated elements
            for(Element element : roundEnv.getElementsAnnotatedWith(typeElement)) {
                // Get Property annotation
                Property property = element.getAnnotation(Property.class);

            }
        }
        return false;
    }

}

这是一个问题,我以前使用过 Javassist,但它取决于类加载器,我认为它不适合 OSGi 应用程序。我想在编译带有Property 注解的类时更改生成的字节码。

【问题讨论】:

  • 一个问题 - 为什么需要这个?不能用其他方式实现吗?
  • 在不使用 APT 或此 API 的情况下,我将需要为每个属性同时注释 setter 和 getter 方法,但如果这可行,我将完全控制如何生成代码。这不是一个纯粹的商业问题,我想知道这是否可能

标签: java properties osgi bytecode code-injection


【解决方案1】:

你试过Google Guice吗?

Google Guice 允许您通过拦截方法来进行一些面向方面的编程。如果这就是您需要做的所有事情,您可以实现一个 MethodInterceptor,它可以让您在运行时覆盖方法。隔离横切关注点非常好。

例如,假设您想阻止某些方法在周末执行,您可以这样注释它们:

@Property
public class SomeClass {
    public Receipt doSometing() {
        // Do something
    }
}

定义一个 MethodInterceptor:

public class PropertyInterceptor implements MethodInterceptor {
  public Object invoke(MethodInvocation invocation) throws Throwable {
    // For example prevent the classes annotated with @Property
    // from being called on weekends
    Calendar today = new GregorianCalendar();
    if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
      throw new IllegalStateException(
          invocation.getMethod().getName() + " not allowed on weekends!");
    }
    return invocation.proceed();
  }
}

然后将拦截器绑定到注解上:

public class PropertyModule extends AbstractModule {
  protected void configure() {
        PropertyInterceptor propertyInterceptor = new PropertyInterceptor();        
        bindInterceptor(Matchers.annotatedWith(Property.class), 
        Matchers.any(), propertyInterceptor);
  }
}

【讨论】:

    【解决方案2】:

    注解处理并不意味着改变现有的类——它只是为了生成额外的代码/资源(在逐个类的基础上,否则你只会在重新编译修改后的源时遇到麻烦)。

    前段时间我尝试Spoon 解决类似的问题:我非常喜欢程序处理器的想法(以及 IDE 集成更),但当时它并不太稳定......

    根据您的用例,AOP 工具(例如:AspectJ)可能比 Spoon 更适合您,而且 - 当然 - 您总是可以使用源代码生成器或实现成熟的 DSL(看看在梦幻般的Xtext)。

    取决于你的队友的规模、流动率和“智力惯性”——你最好忍受普通 java 的痛苦,而不是引入新的工具/技术、组建同事和整合新的CI 系统中的工具。仔细权衡成本/收益。

    【讨论】:

      【解决方案3】:

      简短的回答是:您不应该在注释处理期间更改源代码。

      我最近遇到了一种情况,该答案不令人满意(请参阅this question)。我的解决方案是使用内部 javac api 以编程方式添加我需要的代码。详情请见my answer to my own question

      我从Project Lombok 获得了灵感,从他们的源代码开始,扔掉了我不需要的所有东西。我认为您不会找到更好的起点。

      顺便说一句,Javassist 可能无济于事,因为您处理的是源代码树,而不是字节码。如果您想使用字节码操作库,您可以在编译后静态执行,也可以在加载类时动态执行此操作,但不能在注释处理期间执行,因为这是一个预编译步骤。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-21
        • 1970-01-01
        • 1970-01-01
        • 2013-01-27
        • 1970-01-01
        • 2011-04-08
        相关资源
        最近更新 更多