Mon, 14 Jan 2013 19:52:36 +0100
7193719: Support repeating annotations in javax.lang.model
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 10 19:38:57 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Jan 14 19:52:36 2013 +0100 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -450,7 +450,7 @@ 1.11 * This is the implementation for {@code 1.12 * javax.lang.model.element.Element.getAnnotationMirrors()}. 1.13 */ 1.14 - public final List<Attribute.Compound> getAnnotationMirrors() { 1.15 + public final List<? extends AnnotationMirror> getAnnotationMirrors() { 1.16 return getRawAttributes(); 1.17 } 1.18 1.19 @@ -462,6 +462,11 @@ 1.20 return JavacElements.getAnnotation(this, annoType); 1.21 } 1.22 1.23 + // This method is part of the javax.lang.model API, do not use this in javac code. 1.24 + public <A extends java.lang.annotation.Annotation> A[] getAnnotations(Class<A> annoType) { 1.25 + return JavacElements.getAnnotations(this, annoType); 1.26 + } 1.27 + 1.28 // TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList 1.29 public java.util.List<Symbol> getEnclosedElements() { 1.30 return List.nil();
2.1 --- a/src/share/classes/com/sun/tools/javac/model/JavacElements.java Thu Jan 10 19:38:57 2013 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Jan 14 19:52:36 2013 +0100 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -27,6 +27,8 @@ 2.11 2.12 import java.lang.annotation.Annotation; 2.13 import java.lang.annotation.Inherited; 2.14 +import java.lang.reflect.InvocationTargetException; 2.15 +import java.lang.reflect.Method; 2.16 import java.util.Map; 2.17 2.18 import javax.lang.model.SourceVersion; 2.19 @@ -96,32 +98,43 @@ 2.20 enter = Enter.instance(context); 2.21 } 2.22 2.23 - 2.24 /** 2.25 - * An internal-use utility that creates a reified annotation. 2.26 + * An internal-use utility that creates a runtime view of an 2.27 + * annotation. This is the implementation of 2.28 + * Element.getAnnotation(Class). 2.29 */ 2.30 public static <A extends Annotation> A getAnnotation(Symbol annotated, 2.31 Class<A> annoType) { 2.32 if (!annoType.isAnnotation()) 2.33 throw new IllegalArgumentException("Not an annotation type: " 2.34 + annoType); 2.35 + Attribute.Compound c; 2.36 + if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) { 2.37 + c = getAttributeOnClass((ClassSymbol)annotated, annoType); 2.38 + } else { 2.39 + c = getAttribute(annotated, annoType); 2.40 + } 2.41 + return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 2.42 + } 2.43 + 2.44 + // Helper to getAnnotation[s] 2.45 + private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated, 2.46 + Class<A> annoType) { 2.47 String name = annoType.getName(); 2.48 - for (Attribute.Compound anno : annotated.getAnnotationMirrors()) 2.49 + 2.50 + for (Attribute.Compound anno : annotated.getRawAttributes()) 2.51 if (name.equals(anno.type.tsym.flatName().toString())) 2.52 - return AnnotationProxyMaker.generateAnnotation(anno, annoType); 2.53 + return anno; 2.54 + 2.55 return null; 2.56 } 2.57 - 2.58 - /** 2.59 - * An internal-use utility that creates a reified annotation. 2.60 - * This overloaded version take annotation inheritance into account. 2.61 - */ 2.62 - public static <A extends Annotation> A getAnnotation(ClassSymbol annotated, 2.63 - Class<A> annoType) { 2.64 + // Helper to getAnnotation[s] 2.65 + private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated, 2.66 + Class<A> annoType) { 2.67 boolean inherited = annoType.isAnnotationPresent(Inherited.class); 2.68 - A result = null; 2.69 + Attribute.Compound result = null; 2.70 while (annotated.name != annotated.name.table.names.java_lang_Object) { 2.71 - result = getAnnotation((Symbol)annotated, annoType); 2.72 + result = getAttribute(annotated, annoType); 2.73 if (result != null || !inherited) 2.74 break; 2.75 Type sup = annotated.getSuperclass(); 2.76 @@ -132,6 +145,188 @@ 2.77 return result; 2.78 } 2.79 2.80 + /** 2.81 + * An internal-use utility that creates a runtime view of 2.82 + * annotations. This is the implementation of 2.83 + * Element.getAnnotations(Class). 2.84 + */ 2.85 + public static <A extends Annotation> A[] getAnnotations(Symbol annotated, 2.86 + Class<A> annoType) { 2.87 + if (!annoType.isAnnotation()) 2.88 + throw new IllegalArgumentException("Not an annotation type: " 2.89 + + annoType); 2.90 + // If annoType does not declare a container this is equivalent to wrapping 2.91 + // getAnnotation(...) in an array. 2.92 + Class <? extends Annotation> containerType = getContainer(annoType); 2.93 + if (containerType == null) { 2.94 + A res = getAnnotation(annotated, annoType); 2.95 + int size; 2.96 + if (res == null) { 2.97 + size = 0; 2.98 + } else { 2.99 + size = 1; 2.100 + } 2.101 + @SuppressWarnings("unchecked") // annoType is the Class for A 2.102 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 2.103 + if (res != null) 2.104 + arr[0] = res; 2.105 + return arr; 2.106 + } 2.107 + 2.108 + // So we have a containing type 2.109 + String name = annoType.getName(); 2.110 + String annoTypeName = annoType.getSimpleName(); 2.111 + String containerTypeName = containerType.getSimpleName(); 2.112 + int directIndex = -1, containerIndex = -1; 2.113 + Attribute.Compound direct = null, container = null; 2.114 + Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]); 2.115 + 2.116 + // Find directly present annotations 2.117 + for (int i = 0; i < rawAttributes.length; i++) { 2.118 + if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 2.119 + directIndex = i; 2.120 + direct = rawAttributes[i]; 2.121 + } else if(containerTypeName != null && 2.122 + containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 2.123 + containerIndex = i; 2.124 + container = rawAttributes[i]; 2.125 + } 2.126 + } 2.127 + // Deal with inherited annotations 2.128 + if (annotated.kind == Kinds.TYP && 2.129 + (annotated instanceof ClassSymbol)) { 2.130 + ClassSymbol s = (ClassSymbol)annotated; 2.131 + if (direct == null && container == null) { 2.132 + direct = getAttributeOnClass(s, annoType); 2.133 + container = getAttributeOnClass(s, containerType); 2.134 + 2.135 + // both are inherited and found, put container last 2.136 + if (direct != null && container != null) { 2.137 + directIndex = 0; 2.138 + containerIndex = 1; 2.139 + } else if (direct != null) { 2.140 + directIndex = 0; 2.141 + } else { 2.142 + containerIndex = 0; 2.143 + } 2.144 + } else if (direct == null) { 2.145 + direct = getAttributeOnClass(s, annoType); 2.146 + if (direct != null) 2.147 + directIndex = containerIndex + 1; 2.148 + } else if (container == null) { 2.149 + container = getAttributeOnClass(s, containerType); 2.150 + if (container != null) 2.151 + containerIndex = directIndex + 1; 2.152 + } 2.153 + } 2.154 + 2.155 + // Pack them in an array 2.156 + Attribute[] contained0 = new Attribute[0]; 2.157 + if (container != null) 2.158 + contained0 = unpackAttributes(container); 2.159 + ListBuffer<Attribute.Compound> compounds = ListBuffer.lb(); 2.160 + for (Attribute a : contained0) 2.161 + if (a instanceof Attribute.Compound) 2.162 + compounds = compounds.append((Attribute.Compound)a); 2.163 + Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]); 2.164 + 2.165 + int size = (direct == null ? 0 : 1) + contained.length; 2.166 + @SuppressWarnings("unchecked") // annoType is the Class for A 2.167 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 2.168 + 2.169 + // if direct && container, which is first? 2.170 + int insert = -1; 2.171 + int length = arr.length; 2.172 + if (directIndex >= 0 && containerIndex >= 0) { 2.173 + if (directIndex < containerIndex) { 2.174 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 2.175 + insert = 1; 2.176 + } else { 2.177 + arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 2.178 + insert = 0; 2.179 + length--; 2.180 + } 2.181 + } else if (directIndex >= 0) { 2.182 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 2.183 + return arr; 2.184 + } else { 2.185 + // Only container 2.186 + insert = 0; 2.187 + } 2.188 + 2.189 + for (int i = 0; i + insert < length; i++) 2.190 + arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 2.191 + 2.192 + return arr; 2.193 + } 2.194 + 2.195 + // Needed to unpack the runtime view of containing annotations 2.196 + private static final Class<? extends Annotation> CONTAINED_BY_CLASS = initContainedBy(); 2.197 + private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod(); 2.198 + 2.199 + private static Class<? extends Annotation> initContainedBy() { 2.200 + try { 2.201 + @SuppressWarnings("unchecked") // java.lang.annotation.ContainedBy extends Annotation by being an annotation type 2.202 + Class<? extends Annotation> c = (Class)Class.forName("java.lang.annotation.ContainedBy"); 2.203 + return c; 2.204 + } catch (ClassNotFoundException e) { 2.205 + return null; 2.206 + } catch (SecurityException e) { 2.207 + return null; 2.208 + } 2.209 + } 2.210 + private static Method initValueElementMethod() { 2.211 + if (CONTAINED_BY_CLASS == null) 2.212 + return null; 2.213 + 2.214 + Method m = null; 2.215 + try { 2.216 + m = CONTAINED_BY_CLASS.getMethod("value"); 2.217 + if (m != null) 2.218 + m.setAccessible(true); 2.219 + return m; 2.220 + } catch (NoSuchMethodException e) { 2.221 + return null; 2.222 + } 2.223 + } 2.224 + 2.225 + // Helper to getAnnotations 2.226 + private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) { 2.227 + // Since we can not refer to java.lang.annotation.ContainedBy until we are 2.228 + // bootstrapping with java 8 we need to get the ContainedBy annotation using 2.229 + // reflective invocations instead of just using its type and element method. 2.230 + if (CONTAINED_BY_CLASS != null && 2.231 + VALUE_ELEMENT_METHOD != null) { 2.232 + // Get the ContainedBy instance on the annotations declaration 2.233 + Annotation containedBy = (Annotation)annoType.getAnnotation(CONTAINED_BY_CLASS); 2.234 + if (containedBy != null) { 2.235 + try { 2.236 + // Get the value element, it should be a class 2.237 + // indicating the containing annotation type 2.238 + @SuppressWarnings("unchecked") 2.239 + Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(containedBy); 2.240 + if (containerType == null) 2.241 + return null; 2.242 + 2.243 + return containerType; 2.244 + } catch (ClassCastException e) { 2.245 + return null; 2.246 + } catch (IllegalAccessException e) { 2.247 + return null; 2.248 + } catch (InvocationTargetException e ) { 2.249 + return null; 2.250 + } 2.251 + } 2.252 + } 2.253 + return null; 2.254 + } 2.255 + // Helper to getAnnotations 2.256 + private static Attribute[] unpackAttributes(Attribute.Compound container) { 2.257 + // We now have an instance of the container, 2.258 + // unpack it returning an instance of the 2.259 + // contained type or null 2.260 + return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values; 2.261 + } 2.262 2.263 public PackageSymbol getPackageElement(CharSequence name) { 2.264 String strName = name.toString(); 2.265 @@ -238,8 +433,10 @@ 2.266 tree.accept(vis); 2.267 if (vis.result == null) 2.268 return null; 2.269 + 2.270 + List<Attribute.Compound> annos = sym.getRawAttributes(); 2.271 return matchAnnoToTree(cast(Attribute.Compound.class, findme), 2.272 - sym.getAnnotationMirrors(), 2.273 + annos, 2.274 vis.result); 2.275 } 2.276 2.277 @@ -442,7 +639,7 @@ 2.278 */ 2.279 public List<Attribute.Compound> getAllAnnotationMirrors(Element e) { 2.280 Symbol sym = cast(Symbol.class, e); 2.281 - List<Attribute.Compound> annos = sym.getAnnotationMirrors(); 2.282 + List<Attribute.Compound> annos = sym.getRawAttributes(); 2.283 while (sym.getKind() == ElementKind.CLASS) { 2.284 Type sup = ((ClassSymbol) sym).getSuperclass(); 2.285 if (!sup.hasTag(CLASS) || sup.isErroneous() || 2.286 @@ -451,7 +648,8 @@ 2.287 } 2.288 sym = sup.tsym; 2.289 List<Attribute.Compound> oldAnnos = annos; 2.290 - for (Attribute.Compound anno : sym.getAnnotationMirrors()) { 2.291 + List<Attribute.Compound> newAnnos = sym.getRawAttributes(); 2.292 + for (Attribute.Compound anno : newAnnos) { 2.293 if (isInherited(anno.type) && 2.294 !containsAnnoOfType(oldAnnos, anno.type)) { 2.295 annos = annos.prepend(anno); 2.296 @@ -465,11 +663,7 @@ 2.297 * Tests whether an annotation type is @Inherited. 2.298 */ 2.299 private boolean isInherited(Type annotype) { 2.300 - for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) { 2.301 - if (anno.type.tsym == syms.inheritedType.tsym) 2.302 - return true; 2.303 - } 2.304 - return false; 2.305 + return annotype.tsym.attribute(syms.inheritedType.tsym) != null; 2.306 } 2.307 2.308 /**
3.1 --- a/src/share/classes/javax/lang/model/element/Element.java Thu Jan 10 19:38:57 2013 -0800 3.2 +++ b/src/share/classes/javax/lang/model/element/Element.java Mon Jan 14 19:52:36 2013 +0100 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -149,6 +149,56 @@ 3.11 <A extends Annotation> A getAnnotation(Class<A> annotationType); 3.12 3.13 /** 3.14 + * Returns an array of all of this element's annotation for the 3.15 + * specified type if such annotations are present, else an empty 3.16 + * array. The annotation may be either inherited or directly 3.17 + * present on this element. This method will look through a container 3.18 + * annotation (if present) if the supplied annotation type is 3.19 + * repeatable. 3.20 + * 3.21 + * <p> The annotations returned by this method could contain an element 3.22 + * whose value is of type {@code Class}. 3.23 + * This value cannot be returned directly: information necessary to 3.24 + * locate and load a class (such as the class loader to use) is 3.25 + * not available, and the class might not be loadable at all. 3.26 + * Attempting to read a {@code Class} object by invoking the relevant 3.27 + * method on the returned annotation 3.28 + * will result in a {@link MirroredTypeException}, 3.29 + * from which the corresponding {@link TypeMirror} may be extracted. 3.30 + * Similarly, attempting to read a {@code Class[]}-valued element 3.31 + * will result in a {@link MirroredTypesException}. 3.32 + * 3.33 + * <blockquote> 3.34 + * <i>Note:</i> This method is unlike others in this and related 3.35 + * interfaces. It operates on runtime reflective information — 3.36 + * representations of annotation types currently loaded into the 3.37 + * VM — rather than on the representations defined by and used 3.38 + * throughout these interfaces. Consequently, calling methods on 3.39 + * the returned annotation object can throw many of the exceptions 3.40 + * that can be thrown when calling methods on an annotation object 3.41 + * returned by core reflection. This method is intended for 3.42 + * callers that are written to operate on a known, fixed set of 3.43 + * annotation types. 3.44 + * </blockquote> 3.45 + * 3.46 + * @param <A> the annotation type 3.47 + * @param annotationType the {@code Class} object corresponding to 3.48 + * the annotation type 3.49 + * @return this element's annotations for the specified annotation 3.50 + * type if present on this element, else an empty array 3.51 + * 3.52 + * @see #getAnnotationMirrors() 3.53 + * @see #getAnnotation() 3.54 + * @see java.lang.reflect.AnnotatedElement#getAnnotations 3.55 + * @see EnumConstantNotPresentException 3.56 + * @see AnnotationTypeMismatchException 3.57 + * @see IncompleteAnnotationException 3.58 + * @see MirroredTypeException 3.59 + * @see MirroredTypesException 3.60 + */ 3.61 + <A extends Annotation> A[] getAnnotations(Class<A> annotationType); 3.62 + 3.63 + /** 3.64 * Returns the modifiers of this element, excluding annotations. 3.65 * Implicit modifiers, such as the {@code public} and {@code static} 3.66 * modifiers of interface members, are included.