When we started Stubbles and implemented the annotation feature we drafted them as first class citizens within the code, being classes containing their data and also with the possibility to contain logic. While this was quite a good idea in the beginning and it offered a lot of possibilities and freedom to implement features which revolve around the usage of annotations, I came to the opinion that it's not such a good idea at all.
The most simplest reason for this is the idea that annotations are markup. They mark (or, to keep the notion, annotate) code as being special or to be treated in some special kind of way, depending on the scenario where the code is used in, with scenario meaning something like creating the object graph for the application, serializing data to XML or into a database, or populating objects with values from a given source. What is common to all these scenarios is that you have some kind of logic which treats arbitrary objects where both logic and treated objects don't know anything about each other. The only thing which ties them together and tells the logic how to to treat the object are annotations, they give hints how the logic should perform in regard to the object.
From a design point of view this makes it clear why annotations should not contain logic. If annotations contain parts of such logic, it becomes splitted and possibly cluttered throughout different classes: in the main class of the logic, possibly in any subclasses which you can and should not prevent if required, and in annotations. It's basically a violation of the
single responsibility principle. The single responsibility of an annotation is to mark up code, not to execute logic which is not related to the markup itself.
A second reason is that logic in annotations does not promote code reusage. It's bound to the specific annotation, and there is no way to reuse it in another scenario without annotations. Probably the logic is useful in another way, were informations about how to treat an object does not come from annotations - than it is really helpful to not have any part of the logic in annotations. Or the other way round, it's even harder to reuse other code within the logic constrained in annotations as you are limited to what you can insert into the scope in which annotations are read and created.
What does this mean for Stubbles? In the past days I've revisited all framework code which makes use of annotations, and changed it in a way that all parts of the logic are in specialised classes which are part of the logic. This allowed to get two improvements: for the filter annotations api this means that annotated filters can now be created in exactly the same manner as filters which are explicitly requested, via the same source and configuration. The other improvement is within the XML serializer, it lead to much clearer and simpler code then we had before. The improvements are part of the next milestone release 1.6.0 (no release date yet).
I'm also questioning the requirement of the possibility to have different annotation classes. However, I did not came to a final conclusion on this issue yet, but in regard to the language and environment I think it might be enough to have a single annotation class which simply works as data container, maybe even to force logic out of annotations this way. On the other hand, having a separate class might be a good way to provide validation of the annotation values and to prevent wrong usage of the annotation.
One might also consider the point of being able to restrict annotations to certain places, e.g. to restrict the usage of annotations just to methods or properties. But is this really required, e.g. does it provide a useful feature? This has to be answered with no if viewed from the logic, as the logic simply ignores annotations on places it does not use. It might be answered with yes as wrongly placed annotations could raise errors and inform the developer he placed the annotation on a wrong place, leading to cleaner code. But, this only comes into play if annotations on such a place are read at all. If an annotation is in the wrong place, but this place is never parsed for annotations, no such error will ever be raised. The question is: does this tiny positive point outweigh the additional complexity for developers who want to create their own logic with annotations? I don't think so, which leaves validation of annotation values as only use case for having separate annotation classes. Currently the trend is towards having a generic annotation class as data container, but for the moment I will leave the possibility to have a specific annotation class in case it becomes clear that a generic class is not always the answer.


