简体   繁体   English

Java 6 - 注释处理器和代码添加

[英]Java 6 - Annotation processor and code addition

I wrote a custom annotation containing metadata for a property and an AnnotationProcessor : 我写了一个自定义注释,其中包含属性和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;
    }

}

Here is the question, I have used Javassist before but it was depending on the class loader and I think it's not appropriate for OSGi applications. 这是一个问题,我之前使用过Javassist,但它依赖于类加载器,我认为它不适合OSGi应用程序。 I want to change the generated bytecode when a class with Property annotation is compiled. 我想在编译具有Property注释的类时更改生成的字节码。

Have you tried Google Guice ? 你试过Google Guice吗?

Google Guice lets you do a bit of Aspect Oriented Programming by intercepting methods. Google Guice允许您通过拦截方法进行面向方面编程。 If that's all you need to do, you can implement a MethodInterceptor that'll let you override methods at runtime. 如果这就是你需要做的全部,你可以实现一个MethodInterceptor,它允许你在运行时覆盖方法。 It's really neat for isolating cross-cutting concerns. 它非常适合隔离交叉问题。

For example, lets say you want to prevent a certain methods from being executed on weekends, you can annotate them as so: 例如,假设您想要阻止某些方法在周末执行,您可以这样注释它们:

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

Define a MethodInterceptor: 定义一个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();
  }
}

And then bind the interceptor to the annotation: 然后将拦截器绑定到注释:

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

The short answer is: you're not supposed to change source code during annotation processing. 简短的回答是:您不应该在注释处理期间更改源代码。

I have had a situation recently where that answer was not satisfactory (see this question ). 我最近遇到的情况是答案不理想(见这个问题 )。 My solutions was to programmatically add the code I needed using the internal javac api. 我的解决方案是使用内部javac api以编程方式添加我需要的代码。 See my answer to my own question for details. 有关详细信息,请参阅我对自己问题的回答

I took the inspiration to this from Project Lombok , starting out with their source code and throwing away everything I didn't need. 我从Project Lombok那里得到了灵感,从他们的源代码开始,扔掉了我不需要的一切。 I don't think you'll find a much better starting point. 我不认为你会找到一个更好的起点。

BTW, Javassist probably won't help, because you are dealing with a source tree, not with byte code. 顺便说一下,Javassist可能无济于事,因为你正在处理源代码树,而不是字节代码。 If you want to use a byte code manipulation library you can do that either statically after compiling or dynamically when loading the classes, but not during annotation processing, because that's a pre-compile step. 如果要使用字节代码操作库,可以在编译后静态地执行,也可以在加载类时动态执行,但不能在注释处理期间执行,因为这是预编译步骤。

Annotation processing is not meant to alter existing classes - it is just for generating additional code/resources (on a class-by-class basis, otherwise you'll run into trouble when re-compiling the modified sources only). 注释处理并不意味着改变现有的类 - 它只是用于生成额外的代码/资源(在逐个类的基础上,否则在仅重新编译修改的源时会遇到麻烦)。

Some time ago I tried Spoon for a similar problem: I liked the idea of a program processor very much (and the IDE integration even more), but it was not really stable at the time... 前段时间我曾尝试使用Spoon来解决类似的问题:我非常喜欢程序处理器的想法(以及更多的IDE集成),但当时它并不是很稳定......

Depending on your use case, an AOP tool (eg: AspectJ ) could suite you better than Spoon, and - of course - you could always use a source code generator or implement a full-blown DSL (take a look at the fantastic Xtext ). 根据您的使用情况,AOP工具(例如: AspectJ )可以比Spoon更好地为您提供服务,当然 - 您可以随时使用源代码生成器或实现完整的DSL(看看精彩的Xtext ) 。

Depending on the size, turnover rate and "intellectual inertia" of your team mates - you could be better off bearing the pains of plain java instead of those of introducing a new tool/technology, forming co-workers and integrating the new tool in your CI system. 根据你的队友的规模,周转率和“智力惯性” - 你可以更好地承受普通java的痛苦而不是引入新工具/技术,形成同事并将新工具集成到你的CI系统。 Weigh costs/benefits carefully. 仔细权衡成本/收益。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM