【问题标题】:Adding programmatic annotations to a Java class向 Java 类添加编程注释
【发布时间】:2015-07-09 06:19:43
【问题描述】:

使用示例:
我想在类字段上添加一个自定义注释 @MyContainer,然后在所有此类字段上自动添加相关的 Hibernate 注释(取决于字段类型和属性)。
另外,我需要在类中添加 JAXB XmlType 注释,并将类型名称基于类名。
我还想根据他们的类型等向字段添加注释。 所有添加的注释都应该在运行时可用(因此 hibernate / JAXB 可以找到它们)。
我知道以下选项:

  1. 预处理类源(错误选项)
  2. 在编译期间使用 javax.annotation.processing API 进行处理
  3. 使用 Java Assist 等工具进行编译后操作
  4. 在类加载过程中使用 java.lang.instrument API 进行操作
  5. 用 AspectJ 来做(不够强大)

我的主要目标是:

  1. 保持类和源之间的同步以进行调试
  2. 支持同时使用 Maven 和 IDE (Eclipse / Intellij)

如果已经做过此类事情的人能推荐完成此类任务的最佳方法(可能还有潜在的陷阱),我将不胜感激。

【问题讨论】:

  • 不生成注解,而是生成hibernate配置可以加载的hibernate映射XML文件(hbm.xml)怎么办?
  • 谢谢,这是个好主意,但我更喜欢注释选项,因为我还需要生成 JAXB 注释(将来可能还会生成其他注释)。

标签: java compiler-construction annotations bytecode-manipulation


【解决方案1】:

这是一个定义自定义注解的代码示例。此@TesterInfo 应用于类级别,存储测试人员详细信息。这显示了返回类型的不同用途——枚举、数组和字符串。

package com.mkyong.test.core;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) //on class level
public @interface TesterInfo {

    public enum Priority {
       LOW, MEDIUM, HIGH
    }

    Priority priority() default Priority.MEDIUM;

    String[] tags() default "";

    String createdBy() default "Mkyong";

    String lastModified() default "03/01/2014";

}

【讨论】:

    【解决方案2】:

    我认为预处理类源应该是您的首选方式。这使您能够使您的源代码与已编译的类同步,这对于您提到的调试很有用。但它也有利于版本控制,因为您可以签入那些生成的注释。如果在编译期间运行它,那么跟踪工具中的问题也更加困难。在 generate-sources 阶段运行代码生成时,IDE 支持也应该没有问题。

    编辑: 快速搜索产生了一些关于程序化 Java 源代码修改的信息 using the eclipse jdtsome thing in netbeans。但这可能值得进行更多研究或本身的问题。

    【讨论】:

    • 感谢您的回答。您能否提供有关解决方案的更多信息,例如可以使用哪个工具来分析源代码并对其进行操作?不利的一面是源代码充满了低级注释并且不太清晰(我想为运行时添加注释)。
    • 如果您担心这可能导致代码不干净,您应该考虑使用当前类的接口并尽可能隐藏带有注释的实现。
    【解决方案3】:

    我想就此提出另一种方法。由于我的first answer 可能涉及编写自己的工具,您也可以尝试更简单的解决方案。正如我希望您对您的类进行单元测试一样,您可以为此类的每个单元测试实现一个基类。在这个基类中有一个测试方法,它检查每个带有@MyContainer 注释的字段是否也具有所需的休眠注释。

    我们基本上做了同样的事情,不是为了注释,而是为了字段的可序列化,并且用这种方法运行得很好。

    【讨论】:

      【解决方案4】:

      要让它在 IDE、命令行构建和运行时最透明地工作,选项 1(使用 APT)和选项 5(使用 AspectJ)将最适合您。

      对于选项 1,您必须实现自己的注释处理器,该处理器将根据您自己的 @MyContainer 注释的存在注入额外的注释。这是用于something similar 的这种方法的示例。

      对于选项 5,您可以简单地使用 annotation declaration。像这样的:

      declare @field : * ((@*..MyContainer *)).*(..) : @OtherAnnotation();
      

      Spring 的 Roo 工具广泛使用选项 5,我当然不能说它不够强大。

      【讨论】:

      • 能否将注解和注解参数基于类/方法/成员信息?例如,我需要检查容器数据类型并在几个可能的休眠注释之间进行选择。另外,我需要根据字段名称等生成休眠注释的列名...
      【解决方案5】:

      上面提到的替代品很少,每种都有其优点和缺点。这就是为什么我认为上述问题没有真正的“正确”答案。我的目的是从社区和过去做过此类事情并有经验的人那里获得意见。我个人选择将Instrument API 与Javassist 一起使用。通过这种方式,类在运行时得到扩展(尽管相同的工具可用于编译后处理)。好处是可以从 JVM 内部加载代理,从而避免处理所有命令行。很高兴听到其他替代方案。
      谢谢,
      阿夫纳

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-17
        • 1970-01-01
        • 1970-01-01
        • 2014-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多