1.1 --- a/src/share/classes/com/sun/tools/javac/model/JavacElements.java Thu Jan 10 19:38:57 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Jan 14 19:52:36 2013 +0100 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2005, 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 @@ -27,6 +27,8 @@ 1.11 1.12 import java.lang.annotation.Annotation; 1.13 import java.lang.annotation.Inherited; 1.14 +import java.lang.reflect.InvocationTargetException; 1.15 +import java.lang.reflect.Method; 1.16 import java.util.Map; 1.17 1.18 import javax.lang.model.SourceVersion; 1.19 @@ -96,32 +98,43 @@ 1.20 enter = Enter.instance(context); 1.21 } 1.22 1.23 - 1.24 /** 1.25 - * An internal-use utility that creates a reified annotation. 1.26 + * An internal-use utility that creates a runtime view of an 1.27 + * annotation. This is the implementation of 1.28 + * Element.getAnnotation(Class). 1.29 */ 1.30 public static <A extends Annotation> A getAnnotation(Symbol annotated, 1.31 Class<A> annoType) { 1.32 if (!annoType.isAnnotation()) 1.33 throw new IllegalArgumentException("Not an annotation type: " 1.34 + annoType); 1.35 + Attribute.Compound c; 1.36 + if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) { 1.37 + c = getAttributeOnClass((ClassSymbol)annotated, annoType); 1.38 + } else { 1.39 + c = getAttribute(annotated, annoType); 1.40 + } 1.41 + return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 1.42 + } 1.43 + 1.44 + // Helper to getAnnotation[s] 1.45 + private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated, 1.46 + Class<A> annoType) { 1.47 String name = annoType.getName(); 1.48 - for (Attribute.Compound anno : annotated.getAnnotationMirrors()) 1.49 + 1.50 + for (Attribute.Compound anno : annotated.getRawAttributes()) 1.51 if (name.equals(anno.type.tsym.flatName().toString())) 1.52 - return AnnotationProxyMaker.generateAnnotation(anno, annoType); 1.53 + return anno; 1.54 + 1.55 return null; 1.56 } 1.57 - 1.58 - /** 1.59 - * An internal-use utility that creates a reified annotation. 1.60 - * This overloaded version take annotation inheritance into account. 1.61 - */ 1.62 - public static <A extends Annotation> A getAnnotation(ClassSymbol annotated, 1.63 - Class<A> annoType) { 1.64 + // Helper to getAnnotation[s] 1.65 + private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated, 1.66 + Class<A> annoType) { 1.67 boolean inherited = annoType.isAnnotationPresent(Inherited.class); 1.68 - A result = null; 1.69 + Attribute.Compound result = null; 1.70 while (annotated.name != annotated.name.table.names.java_lang_Object) { 1.71 - result = getAnnotation((Symbol)annotated, annoType); 1.72 + result = getAttribute(annotated, annoType); 1.73 if (result != null || !inherited) 1.74 break; 1.75 Type sup = annotated.getSuperclass(); 1.76 @@ -132,6 +145,188 @@ 1.77 return result; 1.78 } 1.79 1.80 + /** 1.81 + * An internal-use utility that creates a runtime view of 1.82 + * annotations. This is the implementation of 1.83 + * Element.getAnnotations(Class). 1.84 + */ 1.85 + public static <A extends Annotation> A[] getAnnotations(Symbol annotated, 1.86 + Class<A> annoType) { 1.87 + if (!annoType.isAnnotation()) 1.88 + throw new IllegalArgumentException("Not an annotation type: " 1.89 + + annoType); 1.90 + // If annoType does not declare a container this is equivalent to wrapping 1.91 + // getAnnotation(...) in an array. 1.92 + Class <? extends Annotation> containerType = getContainer(annoType); 1.93 + if (containerType == null) { 1.94 + A res = getAnnotation(annotated, annoType); 1.95 + int size; 1.96 + if (res == null) { 1.97 + size = 0; 1.98 + } else { 1.99 + size = 1; 1.100 + } 1.101 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.102 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.103 + if (res != null) 1.104 + arr[0] = res; 1.105 + return arr; 1.106 + } 1.107 + 1.108 + // So we have a containing type 1.109 + String name = annoType.getName(); 1.110 + String annoTypeName = annoType.getSimpleName(); 1.111 + String containerTypeName = containerType.getSimpleName(); 1.112 + int directIndex = -1, containerIndex = -1; 1.113 + Attribute.Compound direct = null, container = null; 1.114 + Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]); 1.115 + 1.116 + // Find directly present annotations 1.117 + for (int i = 0; i < rawAttributes.length; i++) { 1.118 + if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.119 + directIndex = i; 1.120 + direct = rawAttributes[i]; 1.121 + } else if(containerTypeName != null && 1.122 + containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.123 + containerIndex = i; 1.124 + container = rawAttributes[i]; 1.125 + } 1.126 + } 1.127 + // Deal with inherited annotations 1.128 + if (annotated.kind == Kinds.TYP && 1.129 + (annotated instanceof ClassSymbol)) { 1.130 + ClassSymbol s = (ClassSymbol)annotated; 1.131 + if (direct == null && container == null) { 1.132 + direct = getAttributeOnClass(s, annoType); 1.133 + container = getAttributeOnClass(s, containerType); 1.134 + 1.135 + // both are inherited and found, put container last 1.136 + if (direct != null && container != null) { 1.137 + directIndex = 0; 1.138 + containerIndex = 1; 1.139 + } else if (direct != null) { 1.140 + directIndex = 0; 1.141 + } else { 1.142 + containerIndex = 0; 1.143 + } 1.144 + } else if (direct == null) { 1.145 + direct = getAttributeOnClass(s, annoType); 1.146 + if (direct != null) 1.147 + directIndex = containerIndex + 1; 1.148 + } else if (container == null) { 1.149 + container = getAttributeOnClass(s, containerType); 1.150 + if (container != null) 1.151 + containerIndex = directIndex + 1; 1.152 + } 1.153 + } 1.154 + 1.155 + // Pack them in an array 1.156 + Attribute[] contained0 = new Attribute[0]; 1.157 + if (container != null) 1.158 + contained0 = unpackAttributes(container); 1.159 + ListBuffer<Attribute.Compound> compounds = ListBuffer.lb(); 1.160 + for (Attribute a : contained0) 1.161 + if (a instanceof Attribute.Compound) 1.162 + compounds = compounds.append((Attribute.Compound)a); 1.163 + Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]); 1.164 + 1.165 + int size = (direct == null ? 0 : 1) + contained.length; 1.166 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.167 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.168 + 1.169 + // if direct && container, which is first? 1.170 + int insert = -1; 1.171 + int length = arr.length; 1.172 + if (directIndex >= 0 && containerIndex >= 0) { 1.173 + if (directIndex < containerIndex) { 1.174 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.175 + insert = 1; 1.176 + } else { 1.177 + arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.178 + insert = 0; 1.179 + length--; 1.180 + } 1.181 + } else if (directIndex >= 0) { 1.182 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.183 + return arr; 1.184 + } else { 1.185 + // Only container 1.186 + insert = 0; 1.187 + } 1.188 + 1.189 + for (int i = 0; i + insert < length; i++) 1.190 + arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 1.191 + 1.192 + return arr; 1.193 + } 1.194 + 1.195 + // Needed to unpack the runtime view of containing annotations 1.196 + private static final Class<? extends Annotation> CONTAINED_BY_CLASS = initContainedBy(); 1.197 + private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod(); 1.198 + 1.199 + private static Class<? extends Annotation> initContainedBy() { 1.200 + try { 1.201 + @SuppressWarnings("unchecked") // java.lang.annotation.ContainedBy extends Annotation by being an annotation type 1.202 + Class<? extends Annotation> c = (Class)Class.forName("java.lang.annotation.ContainedBy"); 1.203 + return c; 1.204 + } catch (ClassNotFoundException e) { 1.205 + return null; 1.206 + } catch (SecurityException e) { 1.207 + return null; 1.208 + } 1.209 + } 1.210 + private static Method initValueElementMethod() { 1.211 + if (CONTAINED_BY_CLASS == null) 1.212 + return null; 1.213 + 1.214 + Method m = null; 1.215 + try { 1.216 + m = CONTAINED_BY_CLASS.getMethod("value"); 1.217 + if (m != null) 1.218 + m.setAccessible(true); 1.219 + return m; 1.220 + } catch (NoSuchMethodException e) { 1.221 + return null; 1.222 + } 1.223 + } 1.224 + 1.225 + // Helper to getAnnotations 1.226 + private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) { 1.227 + // Since we can not refer to java.lang.annotation.ContainedBy until we are 1.228 + // bootstrapping with java 8 we need to get the ContainedBy annotation using 1.229 + // reflective invocations instead of just using its type and element method. 1.230 + if (CONTAINED_BY_CLASS != null && 1.231 + VALUE_ELEMENT_METHOD != null) { 1.232 + // Get the ContainedBy instance on the annotations declaration 1.233 + Annotation containedBy = (Annotation)annoType.getAnnotation(CONTAINED_BY_CLASS); 1.234 + if (containedBy != null) { 1.235 + try { 1.236 + // Get the value element, it should be a class 1.237 + // indicating the containing annotation type 1.238 + @SuppressWarnings("unchecked") 1.239 + Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(containedBy); 1.240 + if (containerType == null) 1.241 + return null; 1.242 + 1.243 + return containerType; 1.244 + } catch (ClassCastException e) { 1.245 + return null; 1.246 + } catch (IllegalAccessException e) { 1.247 + return null; 1.248 + } catch (InvocationTargetException e ) { 1.249 + return null; 1.250 + } 1.251 + } 1.252 + } 1.253 + return null; 1.254 + } 1.255 + // Helper to getAnnotations 1.256 + private static Attribute[] unpackAttributes(Attribute.Compound container) { 1.257 + // We now have an instance of the container, 1.258 + // unpack it returning an instance of the 1.259 + // contained type or null 1.260 + return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values; 1.261 + } 1.262 1.263 public PackageSymbol getPackageElement(CharSequence name) { 1.264 String strName = name.toString(); 1.265 @@ -238,8 +433,10 @@ 1.266 tree.accept(vis); 1.267 if (vis.result == null) 1.268 return null; 1.269 + 1.270 + List<Attribute.Compound> annos = sym.getRawAttributes(); 1.271 return matchAnnoToTree(cast(Attribute.Compound.class, findme), 1.272 - sym.getAnnotationMirrors(), 1.273 + annos, 1.274 vis.result); 1.275 } 1.276 1.277 @@ -442,7 +639,7 @@ 1.278 */ 1.279 public List<Attribute.Compound> getAllAnnotationMirrors(Element e) { 1.280 Symbol sym = cast(Symbol.class, e); 1.281 - List<Attribute.Compound> annos = sym.getAnnotationMirrors(); 1.282 + List<Attribute.Compound> annos = sym.getRawAttributes(); 1.283 while (sym.getKind() == ElementKind.CLASS) { 1.284 Type sup = ((ClassSymbol) sym).getSuperclass(); 1.285 if (!sup.hasTag(CLASS) || sup.isErroneous() || 1.286 @@ -451,7 +648,8 @@ 1.287 } 1.288 sym = sup.tsym; 1.289 List<Attribute.Compound> oldAnnos = annos; 1.290 - for (Attribute.Compound anno : sym.getAnnotationMirrors()) { 1.291 + List<Attribute.Compound> newAnnos = sym.getRawAttributes(); 1.292 + for (Attribute.Compound anno : newAnnos) { 1.293 if (isInherited(anno.type) && 1.294 !containsAnnoOfType(oldAnnos, anno.type)) { 1.295 annos = annos.prepend(anno); 1.296 @@ -465,11 +663,7 @@ 1.297 * Tests whether an annotation type is @Inherited. 1.298 */ 1.299 private boolean isInherited(Type annotype) { 1.300 - for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) { 1.301 - if (anno.type.tsym == syms.inheritedType.tsym) 1.302 - return true; 1.303 - } 1.304 - return false; 1.305 + return annotype.tsym.attribute(syms.inheritedType.tsym) != null; 1.306 } 1.307 1.308 /**