--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 10 19:38:57 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Jan 14 19:52:36 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -450,7 +450,7 @@
* This is the implementation for {@code
* javax.lang.model.element.Element.getAnnotationMirrors()}.
*/
- public final List<Attribute.Compound> getAnnotationMirrors() {
+ public final List<? extends AnnotationMirror> getAnnotationMirrors() {
return getRawAttributes();
}
@@ -462,6 +462,11 @@
return JavacElements.getAnnotation(this, annoType);
}
+ // This method is part of the javax.lang.model API, do not use this in javac code.
+ public <A extends java.lang.annotation.Annotation> A[] getAnnotations(Class<A> annoType) {
+ return JavacElements.getAnnotations(this, annoType);
+ }
+
// TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList
public java.util.List<Symbol> getEnclosedElements() {
return List.nil();
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java Thu Jan 10 19:38:57 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Jan 14 19:52:36 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Map;
import javax.lang.model.SourceVersion;
@@ -96,32 +98,43 @@
enter = Enter.instance(context);
}
-
/**
- * An internal-use utility that creates a reified annotation.
+ * An internal-use utility that creates a runtime view of an
+ * annotation. This is the implementation of
+ * Element.getAnnotation(Class).
*/
public static <A extends Annotation> A getAnnotation(Symbol annotated,
Class<A> annoType) {
if (!annoType.isAnnotation())
throw new IllegalArgumentException("Not an annotation type: "
+ annoType);
- String name = annoType.getName();
- for (Attribute.Compound anno : annotated.getAnnotationMirrors())
- if (name.equals(anno.type.tsym.flatName().toString()))
- return AnnotationProxyMaker.generateAnnotation(anno, annoType);
- return null;
+ Attribute.Compound c;
+ if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) {
+ c = getAttributeOnClass((ClassSymbol)annotated, annoType);
+ } else {
+ c = getAttribute(annotated, annoType);
+ }
+ return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType);
}
- /**
- * An internal-use utility that creates a reified annotation.
- * This overloaded version take annotation inheritance into account.
- */
- public static <A extends Annotation> A getAnnotation(ClassSymbol annotated,
- Class<A> annoType) {
+ // Helper to getAnnotation[s]
+ private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated,
+ Class<A> annoType) {
+ String name = annoType.getName();
+
+ for (Attribute.Compound anno : annotated.getRawAttributes())
+ if (name.equals(anno.type.tsym.flatName().toString()))
+ return anno;
+
+ return null;
+ }
+ // Helper to getAnnotation[s]
+ private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated,
+ Class<A> annoType) {
boolean inherited = annoType.isAnnotationPresent(Inherited.class);
- A result = null;
+ Attribute.Compound result = null;
while (annotated.name != annotated.name.table.names.java_lang_Object) {
- result = getAnnotation((Symbol)annotated, annoType);
+ result = getAttribute(annotated, annoType);
if (result != null || !inherited)
break;
Type sup = annotated.getSuperclass();
@@ -132,6 +145,188 @@
return result;
}
+ /**
+ * An internal-use utility that creates a runtime view of
+ * annotations. This is the implementation of
+ * Element.getAnnotations(Class).
+ */
+ public static <A extends Annotation> A[] getAnnotations(Symbol annotated,
+ Class<A> annoType) {
+ if (!annoType.isAnnotation())
+ throw new IllegalArgumentException("Not an annotation type: "
+ + annoType);
+ // If annoType does not declare a container this is equivalent to wrapping
+ // getAnnotation(...) in an array.
+ Class <? extends Annotation> containerType = getContainer(annoType);
+ if (containerType == null) {
+ A res = getAnnotation(annotated, annoType);
+ int size;
+ if (res == null) {
+ size = 0;
+ } else {
+ size = 1;
+ }
+ @SuppressWarnings("unchecked") // annoType is the Class for A
+ A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
+ if (res != null)
+ arr[0] = res;
+ return arr;
+ }
+
+ // So we have a containing type
+ String name = annoType.getName();
+ String annoTypeName = annoType.getSimpleName();
+ String containerTypeName = containerType.getSimpleName();
+ int directIndex = -1, containerIndex = -1;
+ Attribute.Compound direct = null, container = null;
+ Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]);
+
+ // Find directly present annotations
+ for (int i = 0; i < rawAttributes.length; i++) {
+ if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
+ directIndex = i;
+ direct = rawAttributes[i];
+ } else if(containerTypeName != null &&
+ containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
+ containerIndex = i;
+ container = rawAttributes[i];
+ }
+ }
+ // Deal with inherited annotations
+ if (annotated.kind == Kinds.TYP &&
+ (annotated instanceof ClassSymbol)) {
+ ClassSymbol s = (ClassSymbol)annotated;
+ if (direct == null && container == null) {
+ direct = getAttributeOnClass(s, annoType);
+ container = getAttributeOnClass(s, containerType);
+
+ // both are inherited and found, put container last
+ if (direct != null && container != null) {
+ directIndex = 0;
+ containerIndex = 1;
+ } else if (direct != null) {
+ directIndex = 0;
+ } else {
+ containerIndex = 0;
+ }
+ } else if (direct == null) {
+ direct = getAttributeOnClass(s, annoType);
+ if (direct != null)
+ directIndex = containerIndex + 1;
+ } else if (container == null) {
+ container = getAttributeOnClass(s, containerType);
+ if (container != null)
+ containerIndex = directIndex + 1;
+ }
+ }
+
+ // Pack them in an array
+ Attribute[] contained0 = new Attribute[0];
+ if (container != null)
+ contained0 = unpackAttributes(container);
+ ListBuffer<Attribute.Compound> compounds = ListBuffer.lb();
+ for (Attribute a : contained0)
+ if (a instanceof Attribute.Compound)
+ compounds = compounds.append((Attribute.Compound)a);
+ Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]);
+
+ int size = (direct == null ? 0 : 1) + contained.length;
+ @SuppressWarnings("unchecked") // annoType is the Class for A
+ A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
+
+ // if direct && container, which is first?
+ int insert = -1;
+ int length = arr.length;
+ if (directIndex >= 0 && containerIndex >= 0) {
+ if (directIndex < containerIndex) {
+ arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
+ insert = 1;
+ } else {
+ arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
+ insert = 0;
+ length--;
+ }
+ } else if (directIndex >= 0) {
+ arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
+ return arr;
+ } else {
+ // Only container
+ insert = 0;
+ }
+
+ for (int i = 0; i + insert < length; i++)
+ arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType);
+
+ return arr;
+ }
+
+ // Needed to unpack the runtime view of containing annotations
+ private static final Class<? extends Annotation> CONTAINED_BY_CLASS = initContainedBy();
+ private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod();
+
+ private static Class<? extends Annotation> initContainedBy() {
+ try {
+ @SuppressWarnings("unchecked") // java.lang.annotation.ContainedBy extends Annotation by being an annotation type
+ Class<? extends Annotation> c = (Class)Class.forName("java.lang.annotation.ContainedBy");
+ return c;
+ } catch (ClassNotFoundException e) {
+ return null;
+ } catch (SecurityException e) {
+ return null;
+ }
+ }
+ private static Method initValueElementMethod() {
+ if (CONTAINED_BY_CLASS == null)
+ return null;
+
+ Method m = null;
+ try {
+ m = CONTAINED_BY_CLASS.getMethod("value");
+ if (m != null)
+ m.setAccessible(true);
+ return m;
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ // Helper to getAnnotations
+ private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) {
+ // Since we can not refer to java.lang.annotation.ContainedBy until we are
+ // bootstrapping with java 8 we need to get the ContainedBy annotation using
+ // reflective invocations instead of just using its type and element method.
+ if (CONTAINED_BY_CLASS != null &&
+ VALUE_ELEMENT_METHOD != null) {
+ // Get the ContainedBy instance on the annotations declaration
+ Annotation containedBy = (Annotation)annoType.getAnnotation(CONTAINED_BY_CLASS);
+ if (containedBy != null) {
+ try {
+ // Get the value element, it should be a class
+ // indicating the containing annotation type
+ @SuppressWarnings("unchecked")
+ Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(containedBy);
+ if (containerType == null)
+ return null;
+
+ return containerType;
+ } catch (ClassCastException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ } catch (InvocationTargetException e ) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+ // Helper to getAnnotations
+ private static Attribute[] unpackAttributes(Attribute.Compound container) {
+ // We now have an instance of the container,
+ // unpack it returning an instance of the
+ // contained type or null
+ return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values;
+ }
public PackageSymbol getPackageElement(CharSequence name) {
String strName = name.toString();
@@ -238,8 +433,10 @@
tree.accept(vis);
if (vis.result == null)
return null;
+
+ List<Attribute.Compound> annos = sym.getRawAttributes();
return matchAnnoToTree(cast(Attribute.Compound.class, findme),
- sym.getAnnotationMirrors(),
+ annos,
vis.result);
}
@@ -442,7 +639,7 @@
*/
public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
Symbol sym = cast(Symbol.class, e);
- List<Attribute.Compound> annos = sym.getAnnotationMirrors();
+ List<Attribute.Compound> annos = sym.getRawAttributes();
while (sym.getKind() == ElementKind.CLASS) {
Type sup = ((ClassSymbol) sym).getSuperclass();
if (!sup.hasTag(CLASS) || sup.isErroneous() ||
@@ -451,7 +648,8 @@
}
sym = sup.tsym;
List<Attribute.Compound> oldAnnos = annos;
- for (Attribute.Compound anno : sym.getAnnotationMirrors()) {
+ List<Attribute.Compound> newAnnos = sym.getRawAttributes();
+ for (Attribute.Compound anno : newAnnos) {
if (isInherited(anno.type) &&
!containsAnnoOfType(oldAnnos, anno.type)) {
annos = annos.prepend(anno);
@@ -465,11 +663,7 @@
* Tests whether an annotation type is @Inherited.
*/
private boolean isInherited(Type annotype) {
- for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) {
- if (anno.type.tsym == syms.inheritedType.tsym)
- return true;
- }
- return false;
+ return annotype.tsym.attribute(syms.inheritedType.tsym) != null;
}
/**
--- a/langtools/src/share/classes/javax/lang/model/element/Element.java Thu Jan 10 19:38:57 2013 -0800
+++ b/langtools/src/share/classes/javax/lang/model/element/Element.java Mon Jan 14 19:52:36 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -149,6 +149,56 @@
<A extends Annotation> A getAnnotation(Class<A> annotationType);
/**
+ * Returns an array of all of this element's annotation for the
+ * specified type if such annotations are present, else an empty
+ * array. The annotation may be either inherited or directly
+ * present on this element. This method will look through a container
+ * annotation (if present) if the supplied annotation type is
+ * repeatable.
+ *
+ * <p> The annotations returned by this method could contain an element
+ * whose value is of type {@code Class}.
+ * This value cannot be returned directly: information necessary to
+ * locate and load a class (such as the class loader to use) is
+ * not available, and the class might not be loadable at all.
+ * Attempting to read a {@code Class} object by invoking the relevant
+ * method on the returned annotation
+ * will result in a {@link MirroredTypeException},
+ * from which the corresponding {@link TypeMirror} may be extracted.
+ * Similarly, attempting to read a {@code Class[]}-valued element
+ * will result in a {@link MirroredTypesException}.
+ *
+ * <blockquote>
+ * <i>Note:</i> This method is unlike others in this and related
+ * interfaces. It operates on runtime reflective information —
+ * representations of annotation types currently loaded into the
+ * VM — rather than on the representations defined by and used
+ * throughout these interfaces. Consequently, calling methods on
+ * the returned annotation object can throw many of the exceptions
+ * that can be thrown when calling methods on an annotation object
+ * returned by core reflection. This method is intended for
+ * callers that are written to operate on a known, fixed set of
+ * annotation types.
+ * </blockquote>
+ *
+ * @param <A> the annotation type
+ * @param annotationType the {@code Class} object corresponding to
+ * the annotation type
+ * @return this element's annotations for the specified annotation
+ * type if present on this element, else an empty array
+ *
+ * @see #getAnnotationMirrors()
+ * @see #getAnnotation()
+ * @see java.lang.reflect.AnnotatedElement#getAnnotations
+ * @see EnumConstantNotPresentException
+ * @see AnnotationTypeMismatchException
+ * @see IncompleteAnnotationException
+ * @see MirroredTypeException
+ * @see MirroredTypesException
+ */
+ <A extends Annotation> A[] getAnnotations(Class<A> annotationType);
+
+ /**
* Returns the modifiers of this element, excluding annotations.
* Implicit modifiers, such as the {@code public} and {@code static}
* modifiers of interface members, are included.