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

发布于 2024-09-24 07:54:16 字数 917 浏览 9 评论 0 原文

我编写了一个包含属性和 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 注释的类时更改生成的字节码。

I wrote a custom annotation containing metadata for a property and an 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. I want to change the generated bytecode when a class with Property annotation is compiled.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦醒时光 2024-10-01 07:54:16

您是否尝试过 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);
  }
}

Have you tried Google Guice?

Google Guice lets you do a bit of Aspect Oriented Programming by intercepting methods. If that's all you need to do, you can implement a MethodInterceptor that'll let you override methods at runtime. 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:

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);
  }
}
故人爱我别走 2024-10-01 07:54:16

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

我最近遇到了一种情况,这个答案并不令人满意(请参阅 这个问题)。我的解决方案是使用内部 javac api 以编程方式添加我需要的代码。请参阅我对自己问题的回答 了解详情。

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

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

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. 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. 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. 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.

夜还是长夜 2024-10-01 07:54:16

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

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

根据您的用例,AOP 工具(例如: AspectJ) 比 Spoon 更适合您,而且 - 当然 - 您始终可以使用源代码生成器或实现成熟的 DSL(看看神奇的 Xtext)。

根据团队成员的规模、人员流动率和“智力惰性”,您可能会更好地承受普通 Java 的痛苦,而不是引入新工具/技术、组建同事并将新工具集成到您的团队中。持续集成系统。仔细权衡成本/收益。

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...

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).

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. Weigh costs/benefits carefully.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文