65.9K
CodeProject 正在变化。 阅读更多。
Home

Java 中的注解转换器

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2008 年 7 月 5 日

CPOL

4分钟阅读

viewsIcon

23143

一篇关于 Java 中注解转换器的文章

引言

自从注解正式进入 Java 语言以来,关于配置应该放在哪里一直存在争论:是在注解中还是在 XML 文件中。

每种方法的优缺点很容易总结:注解允许您将配置系统放在它应用的 Java 源代码附近,但更改它需要 Java 知识和重新编译。 另一方面,XML 文件通常易于修改,并且可以在运行时重新读取(有时甚至无需重新启动您的应用程序),但它们非常冗长且编辑容易出错。

通常在这种情况下,正确的做法是混合使用这些方法。 例如,我一直遵循的一个经验法则是“任何引用 Java 元素(包、类、方法)的配置参数都应在注解中指定”(例如,@Test @Transaction),并且“任何适用于您的整个应用程序的配置参数可能都属于 XML 文件”(例如,输出日志文件的名称或目标 Web 服务器)。

最近,另一种结合这两种技术的方案也受到了密切关注:能够使用 XML 文件覆盖 Java 注解。 我还没有遇到一个可以声称它是事实标准的该想法的实现,并且在这一点上,我怀疑这种方法不太可能流行起来,因为它遭受了“两者的最坏情况”综合症。

这就是原因。

代码

考虑以下简单代码

public class Mytest {
    @Test(invocationCount = 10)
        public void verify() {
            // ...
    }
}

这指示 TestNG 调用 verify() 测试方法十次。

如果我想在运行时覆盖这个值,我发现自己必须编写一段相当复杂的 XML 代码,以便精确定位我试图覆盖的确切注解。 它可能看起来像这样

<override-annotation>
  <package name="org.foo.tests">
    <class name="MyClass">
      <method name="verify">
        <annotation name="org.testng.Test">
          <attribute name="invocationCount" value="15" />
        </annotation>
      </method>
    </class>
  </package>
</override-annotation>

当然,您可能想出一种方法来捕获覆盖(注解/属性部分),以便您可以在 XML 文件中的其他地方重用它,以防您希望此覆盖应用于多个方法。 这可以通过定义一个“override-ref”来实现,您将在 XML 文件的顶部定义它,并在整个 XML 文件中重复使用它(就像 ant 的 classpath-ref 一样)。

这已经做了很多工作(而且很难阅读),而且非常脆弱,因为它很可能会在您决定重命名您的类或方法名时中断(IDE 正在开始将重构扩展到非 Java 文件,但我们还没有完全实现)。

由于这些缺点,我一直在使用 TestNG 进行略有不同的方法,它允许您在 Java 中指定此运行时覆盖。 同样,它不是万能药,并且遭受了上述的一些妥协,但是如果您可以接受如果修改覆盖则必须重新编译它的想法(但不是您尝试覆盖的带注解的代码,所以这已经是一个进步了),实际上它很容易实现。

TestNG 引入了以下接口

public interface IAnnotationTransformer {
    public void transform(ITest annotation, Class testClass,
                          Constructor testConstructor, Method testMethod);
}

您像这样使用它

public class MyTransformer implements IAnnotationTransformer
{
    public void transform(ITest annotation, Class testClass,
                          Constructor testConstructor, Method testMethod)  {
        if ("verify".equals(testMethod.getName())) {
            annotation.setInvocationCount(15);
        }
    }
}

观察

以下是关于此技术的一些观察结果

  • 这个想法是,每当 TestNG 解析 @Test 注解时,它会在使用它之前通过注解转换器运行它。
  • 该方法的三个额外参数让您知道在哪里找到了此注解(在类、构造函数或方法上)。 这三个参数中只有一个是非空的。
  • 请注意,transform() 方法的参数是 ITest。 这是因为 TestNG 支持标准注解和 JavaDoc 注解,所以 ITest 是一个简单的外观对象,它代表 @Test (JDK) 或 @testng.test (JavaDoc) 注解。 在更通用的框架中,该参数可能直接是注解的类型,尽管仍然有一些问题需要解决(参见下一点)。
  • 这种方法需要对注解的写入访问权限,这在当前的 JDK 实现中是不可能的。 您可以通过使用外观来解决此限制,该外观可以作为动态代理生成。

注解转换器的优点是它们非常强大:将它们应用于多种方法、多个类、一个类的所有方法或一个包的所有方法等等非常容易。

注解转换器已经在 TestNG Subversion depot 中实现,并且它们将在 TestNG 5.3 发布时公开提供(很快)。

© . All rights reserved.