AnyAnnotation Proposal

Joe Darcy joe.darcy at oracle.com
Tue Feb 7 16:17:31 PST 2012


Thanks for sending this in Reinier.  From skimming the proposal, you and 
your team seems to have responsibly looked at the major areas 
potentially impacted by such a change.  As previously covered on this 
list, sending in a JEP is the official way to proceed to try to get this 
into JDK 8.  Due to other in-progress work, I won't be able to offer an 
analysis of the AnyAnnotation feature to coin-dev for a while.

Cheers,

-Joe

On 02/06/2012 03:40 PM, Reinier Zwitserloot wrote:
> # The AnyAnnotation feature
>
> ___v1.0___
>
> Currently, the JLS specifies that only a direct subtype of
> `java.lang.annotation.Annotation`, defined using the `public @interface`
> syntax, is actually an annotation type, and that the return type of any
> member of an annotation declaration can only be an annotation type (or a
> primitive, String, Class, or a 1-dimensional array). It is therefore not
> possible in java 1.7 to create a member of an annotation declaration that
> implies 'any annotation is legal here'.
>
> This proposal addresses the lack of this feature. It also moves java closer
> towards supporting hierarchical annotations (the ability to have one
> annotation declaration extend something other than
> `java.lang.annotation.Annotation` itself). In a nutshell, the proposed
> changes:
>
> * Allow `java.lang.annotation.Annotation` as a valid return type for
> annotation declaration members (in JDK 1.7 this is not legal). Using this
> class as return type means any annotation is intended to be legal.
> * Update the JLS to reflect this change (no changes to javadoc, reflection
> core API, and JVM specification needed).
> * Patch an assert statement in the reflection core API, and 2 lines in
> javac, to support the spec.
> * Add a new loop detection scheme to avoid an endless loop in the `default`
> construction of an annotation declaration member.
> * Expand on the impact this change will have, both in regards to which
> tooling options now become possible and what impact this change can have on
> existing tools.
>
> ## Authors
>
> * Reinier Zwitserloot (r.zwitserloot at projectlombok.org)
> * Roel Spilker (r.spilker at projectlombok.org)
> * Sander Koning (s.koning at projectlombok.org)
> * Robbert Jan Grootjans (r.grootjans at projectlombok.org)
>
> ## Try it right now!
>
> A special try-it-out javac agent is available here:
>
> [
> http://projectlombok.org/anyannotation](http://projectlombok.org/anyannotation)
>
> This agent 'live patches' any javac7 in memory only, so you can start
> experimenting right away with this feature.
>
> ## Changes required in the JDK and associated documentation
>
> ### JVM Specification: Zero changes required
>
> _Based on [Java Virtual Machine Specification SE7][JVMS]_
>
> 1. For annotations themselves: Section 4.7.16 - **The
> RuntimeVisibleAnnotations attribute** through Section 4.7.19 - **The
> RuntimeInvisibleParameterAnnotations attribute** specify how annotations
> should be encoded in the class file. These sections say the only way to
> store an annotation inside an annotation is as a new annotation block, and
> such a block _includes_ the type of the annotation. Thus, in `@Foo(@Bar)`,
> there is always a pointer to the constant pool entry with
> `com.package.Bar`. It is therefore not necessary to rely on the signatures
> available in the `Foo` type to understand its parameter, and therefore no
> change is necessary to the class file format to support the case where
> `@Foo`'s parameter is of type `Annotation`.
>
> 2. For annotation type declarations, the JVMS basically contains no
> specifications. They are just plain interfaces with a bit set
> (`ACC_ANNOTATION` - see section 4.1 `access_flags`). The only new aspect
> (other than the `ACC_ANNOTATION` bit, which is not affected by this
> proposal) is the classfile encoding of the `default` value feature of an
> annotation declaration member, which is described in section 4.7.20 - **The
> AnnotationDefault attribute**. The format of this attribute is explained in
> terms of section 4.7.16's annotation structure, which already supports this
> proposal without any changes required. There is absolutely no mention that
> the value of an _AnnotationDefault_ block has to match the type of the
> `method_info`'s return type (that aspect of the annotation spec is covered
> in the JLS only). In other words, the JVMS doesn't actually consider `int
> foo() default "Hello, World!";` illegal, though javac obviously would
> refuse to emit a class file if you tried it. This means that `Annotation
> onMethod() default @Deprecated;` isn't treated as illegal by the JVMS
> either, and thus the JVMS needs no updates to reflect that this would be a
> legal construct now. There is furthermore no commentary about the fact that
> the return type of an element of an `ACC_ANNOTATION` type can only be a
> primitive, String, Class, an annotation type, or a 1-dimensional array of
> those. Therefore, no comment needs to be added to explain that
> `java.lang.annotation.Annotation` is also legal even though it is not an
> annotation type according to the JLS.
>
> ### JLS Specification: A few changes required
>
> _based on [Java Language Specification SE7][JLS]_
>
> 1. 9.6 - **Annotation Types** This introductory section describes the
> actual declaration of an annotation type; no changes needed.
>
> 2. 9.6.1 - **Annotation Type Elements** requires two changes:
>
> _old:_
>
> It is a compile-time error if the return type of a method declared in an
> annotation
>   type is not one of the following: a primitive type, String, Class, any
> parameterized
> invocation of Class, an enum type (S8.9), an annotation type, or an array
> type
>   (S10) whose element type is one of the preceding types.
>
> _new:_
>   It is a compile-time error if the return type of a method declared in an
> annotation
>   type is not one of the following: a primitive type, String, Class, any
> parameterized
> invocation of Class, an enum type (S8.9), an annotation type,
> `java.lang.annotation.Annotation`,
>   or an array type (S10) whose element type is one of the preceding types.
>   [smaller]
> If the return type of an annotation method is declared to be
> `java.lang.annotation.Annotation` (or its array), any annotation (S9.7) is
> a valid value:
>   @interface Getter {
> Annotation[] onMethod() default {@NonNull};
>   }
> [/smaller]
>   _old:_
>   It is a compile-time error if an annotation type declaration T contains an
> element
>   of type T, either directly or indirectly.
>   [smaller]
>   For example, this is illegal:
>   @interface SelfRef { SelfRef value(); }
>   and so is this:
>   @interface Ping { Pong value(); }
> @interface Pong { Ping value(); }
> [/smaller]
>   _new (optional change; add an example to clarify):_
>   [smaller]
> For example, this is illegal:
>   @interface SelfRef { SelfRef value(); }
>   and so is this:
>   @interface Ping { Pong value(); }
> @interface Pong { Ping value(); }
>   as is this:
>   @interface SelfRef { Annotation value() default @SelfRef; }
> [/smaller]
>
> 3. 9.6.2 - **Defaults for Annotation Type Elements** requires no changes.
> The relevant paragraph reads:
>
> It is a compile-time error if the type of the element is not commensurate
> (S9.7) with
> the default value specified.
>
> After applying the required changes to sections S9.6.1 and S9.7.1, this
> statement is still valid.
>
> 4. 9.6.3 - **Predefined Annotation Types** requires no changes.
>
> 5. 9.7 - **Annotations** requires no changes (this is an introduction
> section).
>
> 6. 9.7.1 - **Normal Annotations** requires one change and one optional
> change.
>
> The production rule for _ElementValue_ does not need changing because it
> already mentions it can consist of an _Annotation_.
>   _old_:
>   The return type of this method defines the element type of the
> element-value pair.
>   _new_:
>   The return type of this method defines the element type of the
> element-value pair.
> If the return type is `java.lang.annotation.Annotation`, any annotation is
> a valid
>   value.
>   _old_:
>   The type of V is assignment compatible (S5.2) with T, and furthermore:
> * If T is a primitive type or String, and V is a constant expression
> (S15.28).
>   * V is not null.
> * If T is Class, or an invocation of Class, and V is a class literal
> (S15.8.2).
>   * If T is an enum type, and V is an enum constant.
>   _append an item to the list as clarification:_
>   * If T is `java.lang.annotation.Annotation`, and V is an annotation.
>
> 7. 9.7.2 - **Marker Annotations** only describes a shorthand notation;
> needs no changes.
>
> 8. 9.7.3 - **Single-Element Annotations** only describes a shorthand
> notation; needs no changes.
>
> 9. 13.5.7 - **Evolution of Annotation Types** needs no changes.
>
> ### Changes to javadoc of existing java.* API: No changes required
>
> 1. method `java.lang.reflect.Method.getDefaultValue()`'s javadoc does not
> mention anything about annotation member's return types being restricted to
> a subset of legal types, therefore no update to include
> `java.lang.annotation.Annotation` in this subset is required.
>
> 2. `java.lang.Class.isAnnotation()` (and `getModifiers()&
> java.lang.reflect.Modifier.ANNOTATION`) is the only aspect of `Class` which
> is different / relevant for annotation types, and it also makes no mention
> of the return type limitations.
>
> 3. Existing annotations in the java base library itself (`@Override`,
> `@Deprecated`, etc - listed in JLS sections 9.6.3.1-9.6.3.7) do not have
> any methods which are an annotation type, nor do any of these types seem
> like they could use one. No updates are required or suggested for any of
> them.
>
> 4. The javadoc on `java.lang.annotation.Annotation` itself remains valid.
> It might be prudent to expand it with a section that explains that it can
> be used as a return type for an annotation method, but the other legal
> return types for annotation declaration members don't have this either.
> Therefore, for consistency's sake, this proposal does not include a change
> to this javadoc.
>
> ### Changes / additions to any of the method signatures of the reflection
> API or any other part of java base: No changes required
>
> * `java.lang.reflect.Method.getDefaultValue()` already returns
> `java.lang.Object` and thus needs no changes.
>
> * No new API is required to reflectively determine that a given annotation
> declaration member's return type is `Annotation`, because the way this
> return type is reflected is via a `java.lang.Class` return type, which is
> already capable of conveying `Annotation` as a value. This part is one of
> the few ways existing tools might break, as they may erroneously assume
> this return value can only be `java.lang.Class.class`,
> `java.lang.String.class`, any of the primitive wrappers, or a type which is
> an annotation type. This method could now also return
> `java.lang.annotation.Annotation` which is not itself an annotation type.
>
> * No new API is required to reflectively read out annotation values, as
> these will still be specific instances of annotations.
>
> * No new API is required to reflectively read out annotation defaults, as
> these, if present, will still be specific instances of annotations.
>
> ### Changes / additions to JVM library reflection core (java.*): No changes
> needed
>
> 1. `java.lang.reflect.Method.getDefaultValue()` delegates work to internal
> implementations and does not contain any code that would cause issues with
> a `java.lang.annotation.Annotation` return type. It does first acquire the
> return type of the method and then asks for an instance of the value that
> 'fits' this return type, but it leaves all checking to the internal
> implementations that provide both of these values (both the return type and
> an instance for the value given the byte array containing the raw
> `annotationDefault` data). The work is deferred to
> `sun.reflect.annotation.AnnotationParser` and
> `sun.reflection.annotation.AnnotationType`, which do need patches (see
> below).
>
> 2. `java.lang.reflect.Method.getAnnotation(java.lang.Class
> annotationClass)` defers work to `sun.reflect.annotation.AnnotationParser`
> and `sun.reflect.annotation.AnnotationType` as well. Same for
> `java.lang.reflect.Field.getAnnotation`, and
> `java.lang.Class.getAnnotation`. `java.lang.Package.getAnnotation` is a
> wrapper around a dummy `java.lang.Class` instance that holds annotation
> data (and thus, it too defers the work). These internal helpers do need
> patches (see below).
>
> ### Changes / additions to internal support classes used by reflective
> core: One tiny change needed to a system assertion
>
> 1. `sun.reflect.annotation.AnnotationType` - no changes necessary.
>
> 2. `sun.reflect.annotation.AnnotationInvocationHandler` - no changes
> necessary. In particular, the `equals()` implementation does not use the
> return type, only member values; all special handling defaults to
> `equals()`, `toString()`, `hashCode()` etc of the member value if the
> member value is an annotation type. annotation instances already have
> working `equals`, `hashCode`, `toString`, etc implementations, therefore no
> changes are necessary.
>
> 3. `sun.reflect.annotation.AnnotationParser` - Minor changes necessary.
>
> _based on [Revision 9b8c96f96a0f of
> AnnotationParser.java][AnnotationParser]_
>
> * method `parseMemberValue` does NOT provide the expected type (parameter
> `memberType`) to the `parseAnnotation` helper method. Therefore, the fact
> that expected type is a previously invalid value
> (`java.lang.annotation.Annotation`) does not have any effect on parsing the
> annotation in the class file data.
>
> * method `parseSig` does not check if the provided type is an annotation
> type. (It really can't, as the type is not guaranteed to be on the
> classpath, and therefore it has no way of knowing if the provided type is
> actually an annotation type. Nevertheless, the code does indeed include no
> such check).
>
> * method 'parseArray' (helper of `parseMemberValue`) contains an assertion
> (which can be enabled with the `-esa` javac option) on line 485 which needs
> updating:
>
> - assert componentType.isAnnotation();
>   + assert componentType.isAnnotation() || componentType ==
> java.lang.annotation.Annotation.class;
>
> ### Changes to javac: Some changes needed
>
> * javac checks that an annotation declaration member's return type is one
> of the allowed types. This check needs to be extended to consider
> `java.lang.annotation.Annotation` a legal return type value as well. No
> change in the way javac builds the class file to represent the annotation
> declaration is required:
>
> In com.sun.tools.javac.comp.Check:2267
> _based on [Revision ce654f4ecfd8 of Check.java][Check]_
>
> - if ((type.tsym.flags()&  Flags.ANNOTATION) != 0) {
>   + if ((type.tsym.flags()&  Flags.ANNOTATION) != 0 ||  ||
> types.isSameType(type, syms.annotationType)) {
>
> * Loop detection: It is now possible to create 'loops' in default values,
> where the default value of an annotation is itself, or, indirectly, some
> other annotation, one of whose methods contains a default value that points
> back itself. Prior to the introduction of this feature, the rule that the
> return types of annotation methods cannot contain a cyclic reference would
> make it impossible for the default value to contain such a loop, but now
> this is no longer true, so a separate loop detection scheme needs to be
> implemented for default values.
>
> NB: The `checkAnnotationResType` method has been renamed in this patch to
> `checkAnnotationElementType` because it is now no longer used just to check
> return types, but also to check the types in a `default` value.
>
> This change is a bit more involved and thus the full patch is listed here
> in posix diff format:
>
> Full patch of com.sun.tools.javac.comp.Check:
> _based on [Revision ce654f4ecfd8 of Check.java][Check]_
>
> 29d28
> <  import java.util.Set;
> 33a33,34
>   >  import com.sun.tools.javac.tree.JCTree.JCAnnotation;
>> import com.sun.tools.javac.tree.JCTree.JCExpression;
>   38a40
>> import com.sun.tools.javac.code.Attribute.Array;
> 40a43
>   >  import com.sun.tools.javac.code.Type;
> 2267c2270
> <          if ((type.tsym.flags()&  Flags.ANNOTATION) != 0) return;
>   ---
>>          if ((type.tsym.flags()&  Flags.ANNOTATION) != 0 ||
> types.isSameType(type, syms.annotationType)) return;
>   2497c2500,2501
> <                  checkAnnotationResType(meth.pos(), meth.restype.type);
>   ---
>>                  checkAnnotationElementType(meth.pos(), meth.restype.type);
>   >                  checkNonCyclicAnnotationDefaultValues(meth);
> 2518c2522,2523
>   <                  checkAnnotationResType(pos,
> ((MethodSymbol)s).type.getReturnType());
> ---
>   >                  checkAnnotationElementType(pos,
> ((MethodSymbol)s).type.getReturnType());
>>                  checkNonCyclicAnnotationDefaultValues(pos,
> (MethodSymbol)s);
>   2526c2531
> <      void checkAnnotationResType(DiagnosticPosition pos, Type type) {
>   ---
>>      void checkAnnotationElementType(DiagnosticPosition pos, Type type) {
>   2533c2538
> <              checkAnnotationResType(pos, types.elemtype(type));
>   ---
>>              checkAnnotationElementType(pos, types.elemtype(type));
> 2539a2545,2579
>   >      private void checkNonCyclicAnnotationDefaultValues(JCMethodDecl
> meth) {
>>          if (!isAnnotationType(meth.restype.type)) return;
>   >          if (meth.defaultValue == null) return;
>>          meth.defaultValue.accept(new TreeScanner() {
>   >              @Override public void visitAnnotation(JCAnnotation tree) {
>>                  checkAnnotationElementType(tree.pos(), tree.type);
>   >                  super.visitAnnotation(tree);
>>              }
>>          });
>   >      }
>>      private void checkNonCyclicAnnotationDefaultValues(final
> DiagnosticPosition pos, MethodSymbol meth) {
>   >          if (!isAnnotationType(meth.type.getReturnType())) return;
>>          if (meth.defaultValue == null) return;
>   >          if (meth.defaultValue.type.tag == TypeTags.ARRAY) {
>>              for (Attribute a : ((Array)meth.defaultValue).values) {
>   >                  checkAnnotationElementType(pos, a.type);
>>              }
>   >          }
>>          else {
>>              checkAnnotationElementType(pos, meth.defaultValue.type);
>   >          }
>>      }
>>
>   >      private boolean isAnnotationType(Type type) {
>>          switch (type.tag) {
>   >          case TypeTags.CLASS:
>>              return types.isSameType(type, syms.annotationType);
>   >          case TypeTags.ARRAY:
>>              return types.isSameType(types.elemtype(type),
> syms.annotationType);
>   >          default:
>>              return false;
>>          }
>   >      }
> * The error message with key 'cyclic.annotation.element' doesn't need
> changing.
>
> * javac checks that an annotation's parameter is type compatible with the
> annotation's declaration. It does this using an 'assignment compatible'
> check, which will work fine with `java.lang.annotation.Annotation` as
> return type of the annotation declaration member method. However, this
> check is entered using an `if` statement which needs to be expanded:
>
> In com.sun.tools.javac.comp.Annotate:224
> _based on [Revision ce654f4ecfd8 of Annotate.java][Annotate]_
>
> - if ((expected.tsym.flags()&  Flags.ANNOTATION) != 0) {
>   + if ((expected.tsym.flags()&  Flags.ANNOTATION) != 0 ||
> types.isSameType(expected, syms.annotationType)) {
>
> * No other changes are required. The error message with key
> `invalid.annotation.member.type` may need to be expanded to explain that
> `Annotation` is also a legal type.
>
> ### Changes to javax.lang.model: Some changes needed
>
> * javax.lang.model mostly requires no changes, except for the feature where
> one can ask javax.lang.model to create an instance of a given annotation
> class, i.e.:
>
> for (Element elem : roundEnv.getRootElements()) {
> SomeAnnotation instanceOfAnnotation =
> elem.getAnnotation(SomeAnnotation.class);
>   }
>
> The implementation of this feature in OpenJDK's javac obtains
> `java.lang.Class` instances (needed to create the proxies) entirely from
> traversing `SomeAnnotation.class` using reflection. As the return types of
> the methods in `SomeAnnotation.class` would be
> `java.lang.annotation.Annotation`, this mechanism is no longer useful.
> Instead, the 'flat name' of the annotation argument itself needs to be
> turned into a `java.lang.Class` by using `Class.forName()`. Also, it is now
> possible for an annotation argument to contain an annotation that is not on
> the classpath of the annotation processor. The right approach is for this
> annotation instance to throw a `TypeMirrorException` as late as is feasible
> (when the annotation method is invoked that would have to return an
> instance of a type that is not available, but not when i.e. `toString()` is
> invoked). A full patch to the appropriate class is listed here (note that
> the alternate strategy of using `Class.forName` is only used for the new
> feature; existing annotations that do not use it are still created by
> traversing the annototation type via reflection):
>
> In com.sun.tools.javac.model.AnnotationProxyMaker
> _based on [Revision ce654f4ecfd8 of
> AnnotationProxyMaker.java][AnnotationProxyMaker]_
>
> 62c62,64
>   <      private final Class<? extends Annotation>  annoType;
> ---
>>      private Class<? extends Annotation>  annoType;
>   >      private final Class<?>  context;
>>      private ClassLoader classLoader;
>   66c68
> <                                   Class<? extends Annotation>  annoType) {
>   ---
>>                                   Class<? extends Annotation>  annoType,
> Class<?>  context) {
>   68a71
>>          this.context = context;
> 77,78c80
>   <          AnnotationProxyMaker apm = new AnnotationProxyMaker(anno,
> annoType);
> <          return annoType.cast(apm.generateAnnotation());
>   ---
>>          return annoType.cast(generateAnnotationInner(anno, annoType,
> annoType, null));
>   80a83,88
>>      private static Object generateAnnotationInner(
>>              Attribute.Compound anno, Class<? extends Annotation>
> annoType, Class<?>  context, ClassLoader classLoader) {
>   >          AnnotationProxyMaker apm = new AnnotationProxyMaker(anno,
> annoType, context);
>>          apm.classLoader = classLoader;
>   >          return apm.generateAnnotation();
>>      }
> 81a90,100
>   >      private ClassLoader getAnnotationClassLoader() {
>>          if (classLoader == null) {
>   >              ClassLoader cl = context.getClassLoader();
>>              // Line above Could cause security exception, but
>   >              // no other part of javac uses doPrivileged;
>>              // in particular line 259 of AnnotationParser also doesn't
> bother,
>   >              // and is in the same boat.
>>             this.classLoader = cl != null ? cl :
> ClassLoader.getSystemClassLoader();
>   >          }
>>          return classLoader;
>>      }
>   85c104,116
> <      private Annotation generateAnnotation() {
> ---
>   >      @SuppressWarnings("unchecked")
>>      private Object generateAnnotation() {
>   >          if (annoType == Annotation.class) {
>>              try {
>>                  Class<? extends Annotation>  clazz = (Class<? extends
> Annotation>)
>   >
> getAnnotationClassLoader().loadClass(anno.type.tsym.flatName().toString());
>>                  annoType = clazz;
>   >                  return AnnotationParser.annotationForMap(clazz,
>>                          getAllReflectedValues());
>   >              } catch (ClassNotFoundException e) {
>>                  return new MirroredTypeExceptionProxy(anno.type);
>   >              }
>>          }
> 170a202
>   >
> 239c271
> <                  value = generateAnnotation(c, nested);
>   ---
>>                  value = generateAnnotationInner(c, nested, context,
> classLoader);
>
> ## Source and binary compatibility
>
> This proposal introduces no new or changed behaviour for any source code
> which is legal today, and no changes to the class file format. Therefore,
> existing source files which compile on javac 1.7 are not affected.
>
> Existing tools also notice no changes for existing source and class files.
> However, newly compiled annotation declarations may now start using
> `java.lang.annotation.Annotation` as return type for members, and some
> existing tools may have assumed the legal set of return values couldn't
> change. These tools will need to be updated.
>
> Technically, it is possible for existing annotations to be 'widened' - any
> return types which used to be a specific annotation type can be generalized
> to `java.lang.annotation.Annotation`, but this might cause problems with
> consumers of this annotation. The same problem occurs for any library
> update where signatures are changed, however.
>
> ## Use cases for this feature
>
> One obvious use case for annotations is generating code. If this feature is
> added to the JDK, it is possible to specify a list of annotations that
> should be put in the generated code. For example, an annotation that will
> generate a POJO with implementations for `equals`, `hashCode`, et cetera:
>
> @GeneratePOJO
> @AddAnnotations(onClass=@SuppressWarnings("all"))
>   public class StudentTemplate {
> @AddAnnotations(onGetter={@NonNull, @javax.persistence.Id})
>   private int unid;
> }
>
> This feature also takes a step towards allowing hierarchical annotation
> definitions (where an annotation extends another annotation type, instead
> of `java.lang.annotation.Annotation`.
>
> ## Testing the feature
>
> These patches, plus a test suite as well as a way to build a 'live patching
> agent' which allows experimenting with these patches, are available here:
>
> * [github repository](http://github.com/rspilker/jdk-proposal.anyannotation)
> - source repository
> * [live agent](http://projectlombok.org/anyannotation) - direct download of
> the agent which allows immediate experimentation with any javac7.
>
> [JVMS]: http://docs.oracle.com/javase/7/specs/jvms/JVMS-JavaSE7.pdf
> [JLS]: http://docs.oracle.com/javase/7/specs/jls/JLS-JavaSE7.pdf
> [AnnotationParser]:
> http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/classes/sun/reflect/annotation/AnnotationParser.java
> [Check]:
> http://hg.openjdk.java.net/jdk7/jdk7/langtools/file/ce654f4ecfd8/src/share/classes/com/sun/tools/javac/comp/Check.java
> [Annotate]:
> http://hg.openjdk.java.net/jdk7/jdk7/langtools/file/ce654f4ecfd8/src/share/classes/com/sun/tools/javac/comp/Annotate.java
> [AnnotationProxyMaker]:
> http://hg.openjdk.java.net/jdk7/jdk7/langtools/file/ce654f4ecfd8/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java
>




More information about the coin-dev mailing list