Mathias Ricken Home Bio CV/Resume Curriculum Vitae (pdf) (doc) (txt) (embedded) Resume (pdf) (doc) (txt) (embedded) Archive on A Concurrent Affair Concutest: A Framework for Testing Concurrent Programs Mint: Multi-stage Programming for Java xajavac: Extended Annotations-Enabled javac LAPT-javac: Local Variable-Enabled javac DrJava IDE Programming for Change: The Temperature Calculator Object-Oriented Design Festival Design Patterns for Parsing Assignments for an Objects-First Curriculum Design Patterns for Marine Biology Simulation Geometry Synthesis DrC# IDE Geometry Synthesis by Analogy COMP 410 - Software Engineering Methodology Past Classes Blog A Concurrent Affair My Academia.edu Papers Talks Teaching |
xajavac: Extended Annotation Enabled javac
Java 5.0 introduced annotations,
meta-data that can be attached to other parts of the program. The annotations are implemented as interfaces, encoded as regular Java class files. Annotation interfaces implicitly implement the interface Parent { ... } interface Parent2 { ... } interface Child extends Parent, Parent2 { ... } @interface ParentAnnot { ... } @interface ParentAnnot2 { ... } @interface ChildAnnod extends ParentAnnot, ParentAnnot2 { ... } // error! Furthermore, annotations may only contain primitive data, strings, class literals (Example: @interface Erroneous { java.lang.annotation.Annotation value(); // error! } Generics are not allowed either. The lack of subtyping and generics leads to very poor code reuse: It is impossible to write one annotation that accepts more than one kind of annotation as member; the exact type of all members has to be determined in the annotation. In the Concutest invariant checker, I would have liked to define annotations that serve as Boolean operators, combining the results of other annotations: @interface InvariantAnnotation { } @interface OnlyThreadWithName extends InvariantAnnotation { String value(); } @interface OnlyEventThread extends InvariantAnnotation { } @interface Or extends InvariantAnnotation { InvariantAnnotation[] value(); } @interface And extends InvariantAnnotation { InvariantAnnotation[] value(); } @Or({@And({@OnlyThreadWithName("foo"), @OnlyEventThread}), @OnlyThreadWithName("bar")}) void f() { } Alas, this was impossible. Even though the When I examined the Java compiler and the class files it produces for annotations, I found nothing that prevented subtyping for annotations. In the compiler, I merely had to remove a few checks to allow the To use the modified compiler, download the xajavac.jar file (using the xajavac Binaries link below) and invoke it using xajavac allows the Formally, I have changed the grammar of Java from what has been published in The Java Language Specification, Third Edition in the following places. Here is the abridged original grammar: AnnotationTypeDeclaration: @ interface Identifier AnnotationTypeBody And here is my changed grammar: AnnotationTypeDeclaration: [final] @ interface Identifier [extends AnnotationTypeList] AnnotationTypeBody AnnotationTypeList: AnnotationType { , AnnotationType} AnnotationType: Identifier As stated before, there is a context-sensitive requirement for the Consider these examples: @interface BaseAnnotation { // java.lang.annotation.Annotation as implicit superclass int value(); } @interface SubAnnotation extends BaseAnnotation { // extends BaseAnnotation String s(); } @interface AnotherAnnotation { // java.lang.annotation.Annotation as implicit superclass Class c(); } @interface ThirdAnnotation { // java.lang.annotation.Annotation as implicit superclass Class value(); } @interface SubSubAnnotation extends SubAnnotation, AnotherAnnotation { // extends both SubAnnotation and AnotherAnnotation } @interface ErroneousAnnotation extends java.lang.annotation.Annotation { // error: Annotation is not an annotation itself int value(); } @interface ErroneousAnnotation2 extends BaseAnnotation { // error: value member already exists in BaseAnnotation // cannot be overridden int value(); } @interface ErroneousAnnotation3 extends BaseAnnotation { // error: value member already exists in BaseAnnotation // cannot be overloaded based on return type String value(); } @interface ErroneousAnnotation4 extends BaseAnnotation, ThirdAnnotation { // error: value member exists in both BaseAnnotation and ThirdAnnotation // ambiguous } The JSR 308: Annotations on Types proposal mentions subtyping for annotations as future improvements but considers it out-of-scope for the current proposal. The JSR 308 proposal listed one problem when annotations allow subtyping: There may be trust issues, because an annotation in a secure framework may be subclassed, and then a non-secure annotation may be used. I don't think this is a major issue: The problem with untrusted code comes up with regular classes and frameworks already. To ensure that an annotation cannot be subclassed, I allowed the final @interface FinalAnnotation { String value(); } // ERROR: cannot inherit from final FinalAnnotation @interface SubAnnotation extends FinalAnnotation { int i(); } The extended reflection API I make available here consists of the All of the public Method[] getMethods() throws SecurityException method in public MethodEx[] getMethods() throws SecurityException in import edu.rice.cs.cunit.subAnnot.*; import java.lang.annot.*; public class Test { public static void main(String[] args) { // create a ClassEx instance from a Class instance ClassEx<Test> c = new ClassEx<Test>(Test.class); MethodEx[] ms = c.getMethods(); // to retrieve a Method instance from a MethodEx instance Method m = ms[0].java; // java is a public final field } } The major change that was necessary to incorporate subtyping for annotations was a change in the semantics of the public <A extends Annotation> A getAnnotation(Class<A> annotationClass) method. First, this method now also considers subclasses of the specified class public <A extends java.lang.annotation.Annotation> java.util.List<A> getAnnotations(ClassEx<A> c) This method could subsume the original For further instructions on how to use the extended reflection API, see the subannot Javadoc. To achieve subtyping for annotations, only minimal changes to the Java compiler had to be made; the class format remains completely unchanged; and the changes to the reflection API that are necessary to allow reflection for annotations with subtyping were easy to implement. In fact, in a future official change of Java, these changes should be intregrated into the reflection classes in Considering how small the changes were, I strongly urge Sun to incorporate subtyping for annotations soon. The binaries and source code to my modified version of javac are available for download here. IMPORTANT: WITH YOUR DOWNLOAD OF THESE FILES, YOU ACCEPT THE JAVA RESEARCH LICENSE 1.5 (review license agreement).
The binaries and the Javadoc for the extended annotation API are available for download here. Acceptance of the Java Research License is not necessary. The source code will be released soon. Below is the source and a Windows binary for a tool that allows you to replace the original javac executable and redirect calls to any other program, for example xajavac.jar. I have also created a compiler adapter for Apache Ant 1.7.0. The single Java source file and the jar file created from it are available for download below. To use the compiler adapter, first make the class available to Ant by adding the build.compiler=org.apache.tools.ant.taskdefs.compilers.Xajavac xajavac.path=path/to/xajavac.jar The compiler adapter can also be used to launch other Java compilers as long as they are contained
in a jar file and have Here are two presentations I gave in a PLT seminar:
And here is my poster for the Corporate Affiliates Meeting at the Computer Science Department of Rice University:
|
|||||
http://www.cs.rice.edu/research/xajavac/index.shtml Copyright © 2002-2011 by Mathias Ricken. All rights reserved. |