Java 中的注解转换器





0/5 (0投票)
一篇关于 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 发布时公开提供(很快)。