Summary
While annotations are a convenient way to specify configuration data for Java applications, annotations lack the flexibility of an external configuration file, including the ability to override configuration values without having to recompile source code. In a recent blog post, Cedric Beust describes a method to transform annotations at runtime.
Advertisement
The debate whether to specify configuration information in the form of annotations on Java source code or in external configuration files, is still ongoing. The current consensus seems to be that configuration that impacts the source code—such as marking a method as @Test—should use annotations, whereas an external file is more suitable for configuration info that impacts the behavior of an application.
While an external configuration file can be changed—and subsequently reloaded by the application—without altering the source code, configuration specified as an annotation can only change by recompiling the source.
In a recent blog post, Annotation Transformers in Java, TestNG author Cedric Beust discusses various approaches to overriding annotations via XML, including:
[An] approach that blends these two techniques has also been under scrutiny recently: being able to override Java annotations with XML files. I haven't come across an implementation of this idea that can claim it's the defacto standard, and at this point, I suspect that this approach is unlikely to take off because it suffers from the "worst of both worlds" syndrome. Here is why. Consider the simple following code:
public class Mytest {
@Test(invocationCount = 10)
public void verify() { // ... }}
This instructs TestNG to invoke the verify() test method ten times. If I want to override this value at runtime, I find myself having to write a fairly complex piece of XML code in order to pinpoint the exact annotation I'm trying to override. It would probably look like this:
I have been working on a slightly different approach with TestNG that lets you specify this runtime override in Java. Again, it's not a silver bullet and suffers from some of the compromises expressed above, but if you can live with the idea that you have to recompile your override if you modify it (but not the annotated code you are trying to override, so it's already a progress), it's actually fairly simple to achieve.
Beust introduces the notion of an annotation transformer interface:
public interface IAnnotationTransformer {
public void transform(ITest annotation,
Class testClass,
Constructor testConstructor,
Method testMethod);
}
An implementation of this interface serves as the mechanism to transform the meaning of a specified annotation:
public class MyTransformer implements IAnnotationTransformer {
public void transform(ITest annotation,
Class testClass,
Constructor testConstructor,
Method testMethod) {
if ("verify".equals(testMethod.getName())) {
annotation.setInvocationCount(15);
}
}
}
Overriding an annotation then does not require recompiling source code of the class that contains the specified annotation. Beust implemented annotation transformers in the upcoming 5.3 release of TestNG. Of this approach, he observes that:
The advantage of annotation transformers is that they can be very powerful: it's very easy to apply them to several methods, several classes, all methods of a class or of a package.
However, he also notes that implementation can be tricky, since, for instance, the current version of the JDK does not provide write access to annotations.
What guidelines do you follow in your projects to decide between annotations and an external configuration file? What do you think of Beust's approach to overriding annotation values?
> The current consensus seems to be that configuration that > impacts the source code—such as marking a method as > <code>@Test</code>—should use annotations, whereas an > n external file is more suitable for configuration info > that impacts the behavior of an application. > > While an external configuration file can be changed—and > subsequently reloaded by the application—without altering > the source code, configuration specified as an annotation > can only change by recompiling the source.
I think what really needs to be considered here is whether a configuration change could break behavior or not. If not, then you can feel comfortable applying the change while the system is running in production and external config files are the best place for the metadata. If a metadata change could break behavior then you'll want to test the change by going through a full release cycle (change code, build, test, deploy).
If you're going to go through a full release cycle then the whole "you don't have to recompile" argument is irrelevant. There is no benefit to not recompiling besides the 5-10 seconds of time savings, which is not worth the tradeoff of having more complex metadata.
For example, Hibernate mappings are often in XML, but annotations provide much simpler configuration. You're not going to change your mappings dynamically at runtime are you? Any changes you make to your mappings (whether in XML or annotations) could potentially be behavior breaking. So annotations seem like a much better choice from my perspective.
My method verify1() is being called 3 times and not 5 times although i am using [annotation.setInvocationCount(5);] I call the testng file (SimpleTest) using a Suite.xml file
Please help not sure where i am going wrong.Also when does the method "transform" get called