While annotations have been very well received by the community, I have
repeatedly been asked at JavaOne about the possibility of overriding certain
annotations later during the cycle (at deployment time).

Here are a few
thoughts on this subject.
 
The overriding is specified in an external XML file which could look like this:

<override>
  <annotation-class names="javax.ejb3.TransactionAttribute" />
  <scope>
    <package names="com.foo" />
    <class names="Account" />
    <method names="deposit withdraw" />
  </scope>
  <overridden-values>
    <value name="value"
           old-value="javax.ejb3.TransactionAttributeType.SUPPORTS" />
           new-value="javax.ejb3.TransactionAttributeType.REQUIRED" />
  </overridden-values>
</override>

An override is specified with three parameters:

  1. What annotation type is being overridden .
  2. Hani pointed out that he didn’t like space-separated names, which I tend
    to agree with.
  3. The syntax should allow for regular expressions, including the
    possibility to exclude certain patterns.
  4. The scope of the override (which Java elements are impacted:  package, class,
    method, field, etc…).
  5. Which values are overridden and what the new values are.

Notice in the file above that "names" is plural, so you can specify several
space-separated elements each time.
 
Anything under a scope is "and’ed" together.  In the example above, only methods
named "deposit()" and "withdraw()" inside the class com.foo.Account will be
candidates for overriding.  We could imagine having several <scope> stanzas to
specify that an "or" should be used instead.
 
The <overridden-values> stanza specifies the new values that need to be applied
to the Java elements targetted by the <scope> stanza.  The first part must be a
valid name of the annotation type (TransactionAttribute.value() in this
example).  Optionally, you can specify an old-value in order to further restrict
the scope of the overriding.  In the above example, overriding will only apply
if the targetted element has a current transaction attribute "SUPPORTS".  If it
doesn’t, the override will not happen.
 
The matching of the values in the XML file to the actual enum type can be
performed through reflection, including enums, since it is possible to retrieve
a String version of each enum value.
 
The API could probably be very similar to the existing one:

AnnotationOverrider ao = new AnnotationOverrider("override.xml");
Method m = ...;  // retrieve the method
TransactionType oa = ao.getAnnotation(m, TransactionType.class);
// oa.value() now contains the overridden annotation

Here are some open questions/concerns that have come up so far:

  • We should be able to override defaults as well.
     
  • Should we make it possible to insert annotations and not just override
    existing ones?
     
  • Specifying compound values could be problematic.
     
  • Is the syntax too verbose?  For example, Bill Burke is suggesting
    to insert entire Java snippets to identify the targets:

    <annotation method="public void setEM(javax.ejb.EntityManager)">
    @javax.ejb.Inject
    </annotation>

    I personally think that writing Java code in an XML file is a very
    strong design smell, and it’s a step backward since we are reintroducing
    redundancy in the programming model (if you rename this method in your
    Java code, you need to remember to update the fragile string in your
    deployment descriptor).

Please let us know what you think.