Using the annotation processor it is also possible for a library to add a new language feature。 Bruce Chapman's prototype "no closures" proposal, for example, uses the technique to provide a mechanism for casting a method to a Single Abstract Method (SAM) type which compiles on top of Java 6。 During our conversation Chapman pointed out that the SAM type also supports free variables, a key aspect of a closure:
The method body can declare additional parameters beyond those required for the Single Abstract Method using the @As。Additional annotation。 These parameters can have values bound to them at the point where you obtain an instance of the SAM type, and are then passed to the method each time it is invoked。
Chapman also set up the Rapt project to explore other uses of the technique, and has added implementations for two language changes - Multiline Strings and XML literals - that were considered for JDK 7 but won't now make it into the final release。 Java could even get a form of closures support using this approach。 When asked about this, Chapman said:
We are just finishing a Swing project which we used it for。 We have found a couple of minor bugs around generic types, one recently discovered remains to be fixed but other than that it seems quite nice to use, and nobody has been wanting to rush back to use conventional anonymous inner classes。
Project Lombok, another project exploring the the annotation processor, pushes the technique still further。 In effect Lombok uses annotation processing as a hook to run a Java agent that re-writes various javac internals based on the annotations。 Since it is manipulating internal classes it is probably not suited to production use (internal classes can change even between minor releases of the JVM) but the project is an eye-opening example of just what can be done using the annotation processor, including:• Support for properties using a pair of @Getter and/or @Setter annotations with varying access levels, e。g。 @Setter(AccessLevel。PROTECTED) private String name;
• The @EqualsAndHashCode annotation, which generates hashCode() and equals() implementations from the fields of your object
•
• The @ToString annotation, which generates an implementation of the toString() method The @data method, which is equivalent to combining @ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields along with a constructor to initialize your final fields文献综述
Other language experimentation, such as removing checked exceptions from Java, can also be done using this approach。
Whilst the annotation processor technique opens up a welcome new route to language experimentation, care needs to be taken that the generated code can be easily read by developers, not just by the machine。 Chapman made a number of suggestions during our conversation:Generate source code not bytecode, and pay attention to formatting (indenting especially) in the generated code。 The compiler won't care whether it is all on one line or not, but your users will。 I even sometimes add comments and javadoc in the source code generated by my annotation processors where appropriate。
Hopefully if the technique becomes more prevalent IDEs will also make it easier to view the code that is to be generated at compile time。
Syntactic Sugar in the IDE
Bruce Chapman also touches on our third technique - moving the syntactic sugar from the language to the IDE - in his blog and he elaborated on his ideas during our conversation。 It is already routine for Java IDEs to create portions of boilerplate code for you such as the getters and setters of a class, but IDE developers are beginning to push the concept further。 JetBrains' IntelliJ 9 offers a terse code block syntax for inner classes similar to a closure, which a developer can also type。 Acting like code folds, these can then be expanded into the full anonymous inner classes which the compiler works with - this allows developers who prefer to stick with the standard anonymous inner class syntax to do so。 A similar plug-in for Eclipse also exists。 The key point here is that the "alternate" syntax is just a view of the actual code which the compiler and any source management tools continue to work with。 Thus the developer should be able to switchviews between either form (like expanding or collapsing a code fold), and anyone without access to the definition of the sugar just sees the normal Java code。 Chapman writes:There are many details to work out in order to make this easily accessible, but long term I see developers relatively easily defining a two way sugaring/desugaring transformation (jackpot is a good start for how this might be done), trying them out, evolving them and sharing the good ones with colleagues and the community。 The advantages of this are almost the same as for a language change, without the disadvantages。 The very best could become ubiquitous and then form the basis of an actual language change if necessary to get rid of any remaining "noise" not possible with this approach。