I've been experimenting with using annotations to give executable specifications to code and generating unit tests for my algebra project. For example, I have an interface with a method to add two objects together, and the properties you would expect from additions are marked as annotations:
interface Group<E> extends Set<E> {
@Commutative @Associative @Identity("zero") @Inverse("neg")
E plus (E, E);
E zero ();
E neg (E e);
}
I have a (partially implemented) annotation processor that generates tests for these properties for any class that claims to implement this interface.
This is an example of "user" annotations: @Commutative
, @Associative
, etc. are implemented as part of the algebra library, not as part of the annotation processing tool; generating new properties with tests is a simple matter of adding a new annotation type with a special method that checks the property.
Annotations have been moderately well-suited to this task, although there are a number of shortcomings. For example, java annotations do not have a notion of inheritance, so my processor has to explicitly search for annotations on all superinterfaces of a class. Also, Java doesn't support marking a method with multiple copies of the same annotation, so I can't write @DistributesOver("foo")
and @DistributesOver("bar")
on the same method.