1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java Mon Mar 18 18:33:13 2013 -0700 1.3 @@ -0,0 +1,412 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 +package com.sun.tools.javac.model; 1.29 + 1.30 +import java.lang.annotation.Annotation; 1.31 +import java.lang.annotation.Inherited; 1.32 +import java.lang.reflect.InvocationTargetException; 1.33 +import java.lang.reflect.Method; 1.34 + 1.35 +import com.sun.tools.javac.code.Attribute; 1.36 +import com.sun.tools.javac.code.Kinds; 1.37 +import com.sun.tools.javac.code.Symbol; 1.38 +import com.sun.tools.javac.code.Symbol.ClassSymbol; 1.39 +import com.sun.tools.javac.code.Type; 1.40 +import com.sun.tools.javac.code.Type.AnnotatedType; 1.41 +import com.sun.tools.javac.util.ListBuffer; 1.42 +import static com.sun.tools.javac.code.TypeTag.CLASS; 1.43 + 1.44 +/** 1.45 + * Utility methods for operating on annotated constructs. 1.46 + * 1.47 + * <p><b>This is NOT part of any supported API. 1.48 + * If you write code that depends on this, you do so at your own 1.49 + * risk. This code and its internal interfaces are subject to change 1.50 + * or deletion without notice.</b></p> 1.51 + */ 1.52 +public class JavacAnnoConstructs { 1.53 + 1.54 + // <editor-fold defaultstate="collapsed" desc="Symbols"> 1.55 + 1.56 + /** 1.57 + * An internal-use utility that creates a runtime view of an 1.58 + * annotation. This is the implementation of 1.59 + * Element.getAnnotation(Class). 1.60 + */ 1.61 + public static <A extends Annotation> A getAnnotation(Symbol annotated, 1.62 + Class<A> annoType) { 1.63 + if (!annoType.isAnnotation()) 1.64 + throw new IllegalArgumentException("Not an annotation type: " 1.65 + + annoType); 1.66 + Attribute.Compound c; 1.67 + if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) { 1.68 + c = getAttributeOnClass((ClassSymbol)annotated, annoType); 1.69 + } else { 1.70 + c = getAttribute(annotated, annoType); 1.71 + } 1.72 + return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 1.73 + } 1.74 + 1.75 + // Helper to getAnnotation[s] 1.76 + private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated, 1.77 + Class<A> annoType) { 1.78 + String name = annoType.getName(); 1.79 + 1.80 + for (Attribute.Compound anno : annotated.getRawAttributes()) { 1.81 + if (name.equals(anno.type.tsym.flatName().toString())) 1.82 + return anno; 1.83 + } 1.84 + 1.85 + return null; 1.86 + } 1.87 + 1.88 + // Helper to getAnnotation[s] 1.89 + private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated, 1.90 + Class<A> annoType) { 1.91 + boolean inherited = annoType.isAnnotationPresent(Inherited.class); 1.92 + Attribute.Compound result = null; 1.93 + while (annotated.name != annotated.name.table.names.java_lang_Object) { 1.94 + result = getAttribute(annotated, annoType); 1.95 + if (result != null || !inherited) 1.96 + break; 1.97 + Type sup = annotated.getSuperclass(); 1.98 + if (!sup.hasTag(CLASS) || sup.isErroneous()) 1.99 + break; 1.100 + annotated = (ClassSymbol) sup.tsym; 1.101 + } 1.102 + return result; 1.103 + } 1.104 + 1.105 + /** 1.106 + * An internal-use utility that creates a runtime view of 1.107 + * annotations. This is the implementation of 1.108 + * Element.getAnnotations(Class). 1.109 + */ 1.110 + public static <A extends Annotation> A[] getAnnotations(Symbol annotated, 1.111 + Class<A> annoType) { 1.112 + if (!annoType.isAnnotation()) 1.113 + throw new IllegalArgumentException("Not an annotation type: " 1.114 + + annoType); 1.115 + // If annoType does not declare a container this is equivalent to wrapping 1.116 + // getAnnotation(...) in an array. 1.117 + Class <? extends Annotation> containerType = getContainer(annoType); 1.118 + if (containerType == null) { 1.119 + A res = getAnnotation(annotated, annoType); 1.120 + int size; 1.121 + if (res == null) { 1.122 + size = 0; 1.123 + } else { 1.124 + size = 1; 1.125 + } 1.126 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.127 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.128 + if (res != null) 1.129 + arr[0] = res; 1.130 + return arr; 1.131 + } 1.132 + 1.133 + // So we have a containing type 1.134 + String name = annoType.getName(); 1.135 + String annoTypeName = annoType.getSimpleName(); 1.136 + String containerTypeName = containerType.getSimpleName(); 1.137 + int directIndex = -1, containerIndex = -1; 1.138 + Attribute.Compound direct = null, container = null; 1.139 + Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]); 1.140 + 1.141 + // Find directly present annotations 1.142 + for (int i = 0; i < rawAttributes.length; i++) { 1.143 + if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.144 + directIndex = i; 1.145 + direct = rawAttributes[i]; 1.146 + } else if(containerTypeName != null && 1.147 + containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.148 + containerIndex = i; 1.149 + container = rawAttributes[i]; 1.150 + } 1.151 + } 1.152 + 1.153 + // Deal with inherited annotations 1.154 + if (annotated.kind == Kinds.TYP && 1.155 + (annotated instanceof ClassSymbol)) { 1.156 + ClassSymbol s = (ClassSymbol)annotated; 1.157 + if (direct == null && container == null) { 1.158 + direct = getAttributeOnClass(s, annoType); 1.159 + container = getAttributeOnClass(s, containerType); 1.160 + 1.161 + // both are inherited and found, put container last 1.162 + if (direct != null && container != null) { 1.163 + directIndex = 0; 1.164 + containerIndex = 1; 1.165 + } else if (direct != null) { 1.166 + directIndex = 0; 1.167 + } else { 1.168 + containerIndex = 0; 1.169 + } 1.170 + } else if (direct == null) { 1.171 + direct = getAttributeOnClass(s, annoType); 1.172 + if (direct != null) 1.173 + directIndex = containerIndex + 1; 1.174 + } else if (container == null) { 1.175 + container = getAttributeOnClass(s, containerType); 1.176 + if (container != null) 1.177 + containerIndex = directIndex + 1; 1.178 + } 1.179 + } 1.180 + 1.181 + // Pack them in an array 1.182 + Attribute[] contained0 = new Attribute[0]; 1.183 + if (container != null) 1.184 + contained0 = unpackAttributes(container); 1.185 + ListBuffer<Attribute.Compound> compounds = ListBuffer.lb(); 1.186 + for (Attribute a : contained0) 1.187 + if (a instanceof Attribute.Compound) 1.188 + compounds = compounds.append((Attribute.Compound)a); 1.189 + Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]); 1.190 + 1.191 + int size = (direct == null ? 0 : 1) + contained.length; 1.192 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.193 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.194 + 1.195 + // if direct && container, which is first? 1.196 + int insert = -1; 1.197 + int length = arr.length; 1.198 + if (directIndex >= 0 && containerIndex >= 0) { 1.199 + if (directIndex < containerIndex) { 1.200 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.201 + insert = 1; 1.202 + } else { 1.203 + arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.204 + insert = 0; 1.205 + length--; 1.206 + } 1.207 + } else if (directIndex >= 0) { 1.208 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.209 + return arr; 1.210 + } else { 1.211 + // Only container 1.212 + insert = 0; 1.213 + } 1.214 + 1.215 + for (int i = 0; i + insert < length; i++) 1.216 + arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 1.217 + 1.218 + return arr; 1.219 + } 1.220 + 1.221 + // </editor-fold> 1.222 + 1.223 + // <editor-fold defaultstate="collapsed" desc="Types"> 1.224 + 1.225 + /** 1.226 + * An internal-use utility that creates a runtime view of an 1.227 + * annotation. This is the implementation of 1.228 + * TypeMirror.getAnnotation(Class). 1.229 + */ 1.230 + public static <A extends Annotation> A getAnnotation(AnnotatedType annotated, Class<A> annoType) { 1.231 + if (!annoType.isAnnotation()) 1.232 + throw new IllegalArgumentException("Not an annotation type: " 1.233 + + annoType); 1.234 + Attribute.Compound c = getAttribute(annotated, annoType); 1.235 + return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 1.236 + } 1.237 + 1.238 + // Helper to getAnnotation[s] 1.239 + private static <A extends Annotation> Attribute.Compound getAttribute(Type annotated, 1.240 + Class<A> annoType) { 1.241 + String name = annoType.getName(); 1.242 + 1.243 + for (Attribute.Compound anno : annotated.getAnnotationMirrors()) { 1.244 + if (name.equals(anno.type.tsym.flatName().toString())) 1.245 + return anno; 1.246 + } 1.247 + 1.248 + return null; 1.249 + } 1.250 + 1.251 + /** 1.252 + * An internal-use utility that creates a runtime view of 1.253 + * annotations. This is the implementation of 1.254 + * TypeMirror.getAnnotationsByType(Class). 1.255 + */ 1.256 + public static <A extends Annotation> A[] getAnnotationsByType(AnnotatedType annotated, Class<A> annoType) { 1.257 + if (!annoType.isAnnotation()) 1.258 + throw new IllegalArgumentException("Not an annotation type: " 1.259 + + annoType); 1.260 + // If annoType does not declare a container this is equivalent to wrapping 1.261 + // getAnnotation(...) in an array. 1.262 + Class <? extends Annotation> containerType = getContainer(annoType); 1.263 + if (containerType == null) { 1.264 + A res = getAnnotation(annotated, annoType); 1.265 + int size; 1.266 + if (res == null) { 1.267 + size = 0; 1.268 + } else { 1.269 + size = 1; 1.270 + } 1.271 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.272 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.273 + if (res != null) 1.274 + arr[0] = res; 1.275 + return arr; 1.276 + } 1.277 + 1.278 + // So we have a containing type 1.279 + String name = annoType.getName(); 1.280 + String annoTypeName = annoType.getSimpleName(); 1.281 + String containerTypeName = containerType.getSimpleName(); 1.282 + int directIndex = -1, containerIndex = -1; 1.283 + Attribute.Compound direct = null, container = null; 1.284 + Attribute.Compound[] rawAttributes = annotated.getAnnotationMirrors().toArray(new Attribute.Compound[0]); 1.285 + 1.286 + // Find directly present annotations 1.287 + for (int i = 0; i < rawAttributes.length; i++) { 1.288 + if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.289 + directIndex = i; 1.290 + direct = rawAttributes[i]; 1.291 + } else if(containerTypeName != null && 1.292 + containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) { 1.293 + containerIndex = i; 1.294 + container = rawAttributes[i]; 1.295 + } 1.296 + } 1.297 + 1.298 + // Pack them in an array 1.299 + Attribute[] contained0 = new Attribute[0]; 1.300 + if (container != null) 1.301 + contained0 = unpackAttributes(container); 1.302 + ListBuffer<Attribute.Compound> compounds = ListBuffer.lb(); 1.303 + for (Attribute a : contained0) { 1.304 + if (a instanceof Attribute.Compound) 1.305 + compounds = compounds.append((Attribute.Compound)a); 1.306 + } 1.307 + Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]); 1.308 + 1.309 + int size = (direct == null ? 0 : 1) + contained.length; 1.310 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.311 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.312 + 1.313 + // if direct && container, which is first? 1.314 + int insert = -1; 1.315 + int length = arr.length; 1.316 + if (directIndex >= 0 && containerIndex >= 0) { 1.317 + if (directIndex < containerIndex) { 1.318 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.319 + insert = 1; 1.320 + } else { 1.321 + arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.322 + insert = 0; 1.323 + length--; 1.324 + } 1.325 + } else if (directIndex >= 0) { 1.326 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.327 + return arr; 1.328 + } else { 1.329 + // Only container 1.330 + insert = 0; 1.331 + } 1.332 + 1.333 + for (int i = 0; i + insert < length; i++) 1.334 + arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 1.335 + 1.336 + return arr; 1.337 + } 1.338 + 1.339 + // </editor-fold> 1.340 + 1.341 + // <editor-fold defaultstate="collapsed" desc="Container support"> 1.342 + 1.343 + // Needed to unpack the runtime view of containing annotations 1.344 + private static final Class<? extends Annotation> REPEATABLE_CLASS = initRepeatable(); 1.345 + private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod(); 1.346 + 1.347 + private static Class<? extends Annotation> initRepeatable() { 1.348 + try { 1.349 + // Repeatable will not be available when bootstrapping on 1.350 + // JDK 7 so use a reflective lookup instead of a class 1.351 + // literal for Repeatable.class. 1.352 + return Class.forName("java.lang.annotation.Repeatable").asSubclass(Annotation.class); 1.353 + } catch (ClassNotFoundException e) { 1.354 + return null; 1.355 + } catch (SecurityException e) { 1.356 + return null; 1.357 + } 1.358 + } 1.359 + 1.360 + private static Method initValueElementMethod() { 1.361 + if (REPEATABLE_CLASS == null) 1.362 + return null; 1.363 + 1.364 + Method m = null; 1.365 + try { 1.366 + m = REPEATABLE_CLASS.getMethod("value"); 1.367 + if (m != null) 1.368 + m.setAccessible(true); 1.369 + return m; 1.370 + } catch (NoSuchMethodException e) { 1.371 + return null; 1.372 + } 1.373 + } 1.374 + 1.375 + // Helper to getAnnotations 1.376 + private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) { 1.377 + // Since we can not refer to java.lang.annotation.Repeatable until we are 1.378 + // bootstrapping with java 8 we need to get the Repeatable annotation using 1.379 + // reflective invocations instead of just using its type and element method. 1.380 + if (REPEATABLE_CLASS != null && 1.381 + VALUE_ELEMENT_METHOD != null) { 1.382 + // Get the Repeatable instance on the annotations declaration 1.383 + Annotation repeatable = (Annotation)annoType.getAnnotation(REPEATABLE_CLASS); 1.384 + if (repeatable != null) { 1.385 + try { 1.386 + // Get the value element, it should be a class 1.387 + // indicating the containing annotation type 1.388 + @SuppressWarnings("unchecked") 1.389 + Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(repeatable); 1.390 + if (containerType == null) 1.391 + return null; 1.392 + 1.393 + return containerType; 1.394 + } catch (ClassCastException e) { 1.395 + return null; 1.396 + } catch (IllegalAccessException e) { 1.397 + return null; 1.398 + } catch (InvocationTargetException e ) { 1.399 + return null; 1.400 + } 1.401 + } 1.402 + } 1.403 + return null; 1.404 + } 1.405 + 1.406 + // Helper to getAnnotations 1.407 + private static Attribute[] unpackAttributes(Attribute.Compound container) { 1.408 + // We now have an instance of the container, 1.409 + // unpack it returning an instance of the 1.410 + // contained type or null 1.411 + return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values; 1.412 + } 1.413 + 1.414 + // </editor-fold> 1.415 +}