Monday, April 16, 2007

Feature Request: External Annotations for Java 7

Annotations in Java allow developers to provide meta-data about a class. This meta-data is used by tools such as JPA, JAXB, JDBC and many others to perform their various functions. However, a developer may only annotate the classes they are writing. They cannot annotate existing classes, such as those provided by J2SE, a third party jar, or those classes generated by tool such as JAXB or wsimport.

When j2EE 5 was new, there was much talk about simplicity, tools no longer required XML descriptor files, since the classes themselves contained the required meta data. The trouble is that only one set of annotations can apply to a class, those annotations that were applied at development time.

Let me give an example of how it would be useful to annotate an existing class. Suppose you are developing an application that works with an existing web-service and you want to store some of the returned objects in a database. The first thing you do is point wsimport at the wsdl file and it generates a bunch of classes. Then you hand edit each class with the appropriate javax.persistence annotations. Ok, this sounds like it will work, but what happens when that wsdl changes slightly (say during development), you have to regenerate all the classes and reapply the persistence annotations, an error prone process to say the least, a unit test could save you some errors, but what could be worse then writing unit test that check annotations:)

It would be much simpler if you could apply those annotations in an external file. Imagine a XML file for annotating a ContactInfo Class that looked something like this:

<annotations>
<class>
<annotation name='javax.persistence.Entity'>
<parameter name='name' valuetype='string'>ContactInformation</parameter>
</annotation>
</class>

<field name='Addresses'>
<annotation name='javax.persistence.OneToMany'>
<parameter name='cascade' valuetype='constant'>javax.persistence.CascadeType.ALL</parameter>
<parameter name='fetch' valuetype='constant'>javax.persistence.FetchType.EAGER</parameter>
</annotation>
</field>

<method name='sendMail' parameters='String,String'>
<annotation name='Deprecated'>
</annotation>
</method>

</annotations>

Maybe or more Java like format would make sense, we could borrow from the interface format, something like:

package org.someone.else's.packages;

@Entity(name='"ContactInformation")
public annotation ContactInfo {

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
protected List<Address> addresses;

@Deprecated public int sendMail(String from, String mode);

}

I image that these annotation files could exists in your Java source. You would place them in a package just as you would a class, so if you wanted to add an annotation to java.awt.Color, you would create the file [srcbase]/java/awt/Color.annotation

This allow javac to check that you are using the new annotations correctly and that you are annotating existing fields and methods. This file (or a 'compiled' version) would also be included in any Jar file you create, so the annotations can be appended at runtime.

you might ask, "Doesn't this just add back the XML configuration files we got rid of?" i would say no, because they are optional, you can always simply annotate a class you are writing in the standard way. Plus, the annotations are all in a standard format and you gain compile time checking.

Also, say you want to distribute a jar that contains your basic data types, but you don't want to include the nasty details of how it maps to your database, then you could simply omit the *.annotation files.

If Properties do find their way into Java and they turn out to be annotation based, then this could provide way of applying annotations to legacy code, since no changes would be required to the source code, simply annotate the existing classes anyway you want.

I would love some feedback on this!
-Lucas