My two-part article series "AOP and metadata: A perfect match" [Update: Link added, since the article is now published], a part of the AOP@Work series, is about to go live on developerWorks. The first part of the series includes a small section on using metadata to extend the underlying language. However, this topic needs a more elaborate discussion, and hence this blog.
The new metadata facility in Java 5.0 can be used to extend the Java language. In this usage model, an annotation processor alters the semantics of program elements marked with special annotations. Such usage of metadata brings interesting possibilities and a few concerns.
The idea of using metadata to extend the language is not new. AOP systems such as AspectWerkz, JBoss AOP, and now the metadata-driven syntax in AspectJ5 (informally called @AspectJ syntax) use this idea to provide aspect-oriented extensions to Java, in which ordinary program elements are reinterpreted as AOP constructs. For example, you can mark a class to function like an aspect, a method as a pointcut or advice, and so on.
We can classify language extensions using metadata into three categories based on how they affect the programs: compile-time extensions, structural modifications, and behavioral modifications.
These extensions make the compiler perform additional tasks but do not affect the compiled code. Java 5.0 already includes examples of this with
@SuppressWarnings annotations (albeit as a standard feature, rather than an extension).
Generalizing this idea, you can imagine extending the compiler to issue custom errors and warnings upon detecting certain usage patterns. For example, we can use a
Const annotation type to implement the functionality of the C++ "const" keyword in Java. Consider the following annotation type:
Now consider the following class that uses this annotation:
The annotation processor would consume the
@Const annotations to produce compile-time errors for any attempts to modify an item while adding or removing from a shopping cart or any attempts to modify the state of shopping cart while querying for the total.
Okay, the language extension using
@Const is only a theoretical possibility, since I don't think it will be of much practical value unless the core Java classes and existing libraries adopt this annotation type and its semantics. Nevertheless, it is an interesting theoretical possibility.
These extensions modify the structure of the program without modifying the behavior. For example, we could use a
@Property annotation to mark fields of a class as properties. An annotation processor then processes the annotations to add a getter method and/or a setter method for each property based on whether it is a read-write, read-only, or write-only property. Essentially, with this extension, you get the property feature support similar to the one in Groovy and C#.
Consider the following annotation type and the associated enumeration type:
Now consider the following class:
The annotation processor would consume the
@Property to translate this class into a byte-code equivalent of the following snippet:
If a getter or setter already existed for a property, the annotation processor would leave it untouched.
We can use the same idea to support certain structural design patterns directly into the extended language. For example, we can implement the singleton pattern by allowing classes to be marked with an annotation. Consider the following annotation and enumeration types:
Now consider a class marked with a
The annotation processor will translate this class into a byte-code equivalent of the following snippet:
The annotation processor could also modify compile-time behavior to flag the presence of unsupportable structures such as non-zero arguments constructors.
These extensions alter the program behavior. For example, they may add additional code to implement security feature in all the program elements with a
@Secure annotation. EJB 3.0 annotations essentially extend the Java language in the same vein. Another good example of this kind of extension is ContractJ that implements DBC in Java.
While implementing behavior modifications through language extension can be useful in some situations, aspect-oriented programming is a much better way to do the job. When implemented using AOP, the behavior logic doesn't disappear into code in an annotation processor, the code expressed remains much more readable, and the debugging process remains natural.
While some of the features described here can be implemented through a pre-processor (generating code) or post processor (modifying byte-code), a more convenient way would be to allow plugins to the compiler. It would not be surprising if a future tool's JSR proposes a standard way to extend the compiler (perhaps called "complet", in the same spirit as "doclet" to use with Javadoc). Perhaps the Pluggable Annotation Processing API (JSR 269) might be the one to standardize such a facility.
Impact on Java
This possibility allows incorporating new features in the language without having to wait for them to make it into the standard. However, abusing this possibility can wreak havoc on the comprehensibility of the programs. Using this possibility to create principled extensions will make Java a more expressive language. AOP systems using annotations to add aspect-oriented features to Java is a good example of principled extensions (in that there is a system behind it -- aspect-oriented programming). Using this possibility to add ad hoc extensions, on the other hand, will make programs hard to follow without the context of the associated annotation processing.
How the community uses the metadata feature in general, and the language-extension use case in particular, will be interesting to watch.