1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/AnnoConstruct.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,249 @@ 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.code; 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 javax.lang.model.AnnotatedConstruct; 1.36 + 1.37 +import com.sun.tools.javac.model.AnnotationProxyMaker; 1.38 +import com.sun.tools.javac.util.List; 1.39 +import com.sun.tools.javac.util.ListBuffer; 1.40 + 1.41 +/** 1.42 + * Common super type for annotated constructs such as Types and Symbols. 1.43 + * 1.44 + * This class should *not* contain any fields since it would have a significant 1.45 + * impact on the javac memory footprint. 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 abstract class AnnoConstruct implements AnnotatedConstruct { 1.53 + 1.54 + 1.55 + // Override to enforce a narrower return type. 1.56 + @Override 1.57 + public abstract List<? extends Attribute.Compound> getAnnotationMirrors(); 1.58 + 1.59 + 1.60 + // This method is part of the javax.lang.model API, do not use this in javac code. 1.61 + protected <A extends Annotation> Attribute.Compound getAttribute(Class<A> annoType) { 1.62 + String name = annoType.getName(); 1.63 + 1.64 + for (Attribute.Compound anno : getAnnotationMirrors()) { 1.65 + if (name.equals(anno.type.tsym.flatName().toString())) 1.66 + return anno; 1.67 + } 1.68 + 1.69 + return null; 1.70 + } 1.71 + 1.72 + 1.73 + @SuppressWarnings("unchecked") 1.74 + protected <A extends Annotation> A[] getInheritedAnnotations(Class<A> annoType) { 1.75 + return (A[]) java.lang.reflect.Array.newInstance(annoType, 0); // annoType is the Class for A 1.76 + } 1.77 + 1.78 + 1.79 + // This method is part of the javax.lang.model API, do not use this in javac code. 1.80 + public <A extends Annotation> A[] getAnnotationsByType(Class<A> annoType) { 1.81 + 1.82 + if (!annoType.isAnnotation()) 1.83 + throw new IllegalArgumentException("Not an annotation type: " 1.84 + + annoType); 1.85 + // If annoType does not declare a container this is equivalent to wrapping 1.86 + // getAnnotation(...) in an array. 1.87 + Class <? extends Annotation> containerType = getContainer(annoType); 1.88 + if (containerType == null) { 1.89 + A res = getAnnotation(annoType); 1.90 + int size = res == null ? 0 : 1; 1.91 + 1.92 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.93 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.94 + if (res != null) 1.95 + arr[0] = res; 1.96 + return arr; 1.97 + } 1.98 + 1.99 + // So we have a containing type 1.100 + String annoTypeName = annoType.getName(); 1.101 + String containerTypeName = containerType.getName(); 1.102 + int directIndex = -1, containerIndex = -1; 1.103 + Attribute.Compound direct = null, container = null; 1.104 + // Find directly (explicit or implicit) present annotations 1.105 + int index = -1; 1.106 + for (Attribute.Compound attribute : getAnnotationMirrors()) { 1.107 + index++; 1.108 + if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) { 1.109 + directIndex = index; 1.110 + direct = attribute; 1.111 + } else if(containerTypeName != null && 1.112 + attribute.type.tsym.flatName().contentEquals(containerTypeName)) { 1.113 + containerIndex = index; 1.114 + container = attribute; 1.115 + } 1.116 + } 1.117 + 1.118 + // Deal with inherited annotations 1.119 + if (direct == null && container == null && 1.120 + annoType.isAnnotationPresent(Inherited.class)) 1.121 + return getInheritedAnnotations(annoType); 1.122 + 1.123 + Attribute.Compound[] contained = unpackContained(container); 1.124 + 1.125 + // In case of an empty legacy container we might need to look for 1.126 + // inherited annos as well 1.127 + if (direct == null && contained.length == 0 && 1.128 + annoType.isAnnotationPresent(Inherited.class)) 1.129 + return getInheritedAnnotations(annoType); 1.130 + 1.131 + int size = (direct == null ? 0 : 1) + contained.length; 1.132 + @SuppressWarnings("unchecked") // annoType is the Class for A 1.133 + A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1.134 + 1.135 + // if direct && container, which is first? 1.136 + int insert = -1; 1.137 + int length = arr.length; 1.138 + if (directIndex >= 0 && containerIndex >= 0) { 1.139 + if (directIndex < containerIndex) { 1.140 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.141 + insert = 1; 1.142 + } else { 1.143 + arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.144 + insert = 0; 1.145 + length--; 1.146 + } 1.147 + } else if (directIndex >= 0) { 1.148 + arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1.149 + return arr; 1.150 + } else { 1.151 + // Only container 1.152 + insert = 0; 1.153 + } 1.154 + 1.155 + for (int i = 0; i + insert < length; i++) 1.156 + arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 1.157 + 1.158 + return arr; 1.159 + } 1.160 + 1.161 + private Attribute.Compound[] unpackContained(Attribute.Compound container) { 1.162 + // Pack them in an array 1.163 + Attribute[] contained0 = null; 1.164 + if (container != null) 1.165 + contained0 = unpackAttributes(container); 1.166 + ListBuffer<Attribute.Compound> compounds = new ListBuffer<>(); 1.167 + if (contained0 != null) { 1.168 + for (Attribute a : contained0) 1.169 + if (a instanceof Attribute.Compound) 1.170 + compounds = compounds.append((Attribute.Compound)a); 1.171 + } 1.172 + return compounds.toArray(new Attribute.Compound[compounds.size()]); 1.173 + } 1.174 + 1.175 + // This method is part of the javax.lang.model API, do not use this in javac code. 1.176 + public <A extends Annotation> A getAnnotation(Class<A> annoType) { 1.177 + 1.178 + if (!annoType.isAnnotation()) 1.179 + throw new IllegalArgumentException("Not an annotation type: " + annoType); 1.180 + 1.181 + Attribute.Compound c = getAttribute(annoType); 1.182 + return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 1.183 + } 1.184 + 1.185 + // Needed to unpack the runtime view of containing annotations 1.186 + private static final Class<? extends Annotation> REPEATABLE_CLASS = initRepeatable(); 1.187 + private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod(); 1.188 + 1.189 + private static Class<? extends Annotation> initRepeatable() { 1.190 + try { 1.191 + // Repeatable will not be available when bootstrapping on 1.192 + // JDK 7 so use a reflective lookup instead of a class 1.193 + // literal for Repeatable.class. 1.194 + return Class.forName("java.lang.annotation.Repeatable").asSubclass(Annotation.class); 1.195 + } catch (ClassNotFoundException | SecurityException e) { 1.196 + return null; 1.197 + } 1.198 + } 1.199 + 1.200 + private static Method initValueElementMethod() { 1.201 + if (REPEATABLE_CLASS == null) 1.202 + return null; 1.203 + 1.204 + Method m = null; 1.205 + try { 1.206 + m = REPEATABLE_CLASS.getMethod("value"); 1.207 + if (m != null) 1.208 + m.setAccessible(true); 1.209 + return m; 1.210 + } catch (NoSuchMethodException e) { 1.211 + return null; 1.212 + } 1.213 + } 1.214 + 1.215 + 1.216 + // Helper to getAnnotationsByType 1.217 + private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) { 1.218 + // Since we can not refer to java.lang.annotation.Repeatable until we are 1.219 + // bootstrapping with java 8 we need to get the Repeatable annotation using 1.220 + // reflective invocations instead of just using its type and element method. 1.221 + if (REPEATABLE_CLASS != null && 1.222 + VALUE_ELEMENT_METHOD != null) { 1.223 + // Get the Repeatable instance on the annotations declaration 1.224 + Annotation repeatable = (Annotation)annoType.getAnnotation(REPEATABLE_CLASS); 1.225 + if (repeatable != null) { 1.226 + try { 1.227 + // Get the value element, it should be a class 1.228 + // indicating the containing annotation type 1.229 + @SuppressWarnings("unchecked") 1.230 + Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(repeatable); 1.231 + if (containerType == null) 1.232 + return null; 1.233 + 1.234 + return containerType; 1.235 + } catch (ClassCastException | IllegalAccessException | InvocationTargetException e) { 1.236 + return null; 1.237 + } 1.238 + } 1.239 + } 1.240 + return null; 1.241 + } 1.242 + 1.243 + 1.244 + // Helper to getAnnotationsByType 1.245 + private static Attribute[] unpackAttributes(Attribute.Compound container) { 1.246 + // We now have an instance of the container, 1.247 + // unpack it returning an instance of the 1.248 + // contained type or null 1.249 + return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values; 1.250 + } 1.251 + 1.252 +}