AnnoConstruct.java revision 2601:8e638f046bf0
11590Srgrimes/* 21590Srgrimes * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 31590Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41590Srgrimes * 51590Srgrimes * This code is free software; you can redistribute it and/or modify it 61590Srgrimes * under the terms of the GNU General Public License version 2 only, as 71590Srgrimes * published by the Free Software Foundation. Oracle designates this 81590Srgrimes * particular file as subject to the "Classpath" exception as provided 91590Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101590Srgrimes * 111590Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121590Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131590Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141590Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151590Srgrimes * accompanied this code). 161590Srgrimes * 171590Srgrimes * You should have received a copy of the GNU General Public License version 181590Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191590Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201590Srgrimes * 211590Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221590Srgrimes * or visit www.oracle.com if you need additional information or have any 231590Srgrimes * questions. 241590Srgrimes */ 251590Srgrimespackage com.sun.tools.javac.code; 261590Srgrimes 271590Srgrimesimport java.lang.annotation.Annotation; 281590Srgrimesimport java.lang.annotation.Inherited; 291590Srgrimesimport java.lang.reflect.InvocationTargetException; 301590Srgrimesimport java.lang.reflect.Method; 311590Srgrimes 321590Srgrimesimport javax.lang.model.AnnotatedConstruct; 331590Srgrimes 3487675Smarkmimport com.sun.tools.javac.model.AnnotationProxyMaker; 3587675Smarkmimport com.sun.tools.javac.util.DefinedBy; 3687675Smarkmimport com.sun.tools.javac.util.DefinedBy.Api; 3787675Smarkmimport com.sun.tools.javac.util.List; 381590Srgrimesimport com.sun.tools.javac.util.ListBuffer; 3928695Scharnier 401590Srgrimes/** 411590Srgrimes * Common super type for annotated constructs such as Types and Symbols. 4287675Smarkm * 431590Srgrimes * This class should *not* contain any fields since it would have a significant 441590Srgrimes * impact on the javac memory footprint. 4587675Smarkm * 4628695Scharnier * <p><b>This is NOT part of any supported API. 471590Srgrimes * If you write code that depends on this, you do so at your own 481590Srgrimes * risk. This code and its internal interfaces are subject to change 491590Srgrimes * or deletion without notice.</b></p> 501590Srgrimes */ 511590Srgrimespublic abstract class AnnoConstruct implements AnnotatedConstruct { 521590Srgrimes 531590Srgrimes 541590Srgrimes // Override to enforce a narrower return type. 551590Srgrimes @Override @DefinedBy(Api.LANGUAGE_MODEL) 561590Srgrimes public abstract List<? extends Attribute.Compound> getAnnotationMirrors(); 5728695Scharnier 5828695Scharnier 5973255Simp // This method is part of the javax.lang.model API, do not use this in javac code. 6025777Sache protected <A extends Annotation> Attribute.Compound getAttribute(Class<A> annoType) { 611590Srgrimes String name = annoType.getName(); 621590Srgrimes 631590Srgrimes for (Attribute.Compound anno : getAnnotationMirrors()) { 641590Srgrimes if (name.equals(anno.type.tsym.flatName().toString())) 651590Srgrimes return anno; 6629434Sache } 671590Srgrimes 68202200Sed return null; 691590Srgrimes } 7083242Sdd 7183242Sdd 7273255Simp @SuppressWarnings("unchecked") 7373255Simp protected <A extends Annotation> A[] getInheritedAnnotations(Class<A> annoType) { 741590Srgrimes return (A[]) java.lang.reflect.Array.newInstance(annoType, 0); // annoType is the Class for A 7573255Simp } 7673255Simp 7773255Simp 7873255Simp // This method is part of the javax.lang.model API, do not use this in javac code. 7973255Simp @DefinedBy(Api.LANGUAGE_MODEL) 801590Srgrimes public <A extends Annotation> A[] getAnnotationsByType(Class<A> annoType) { 811590Srgrimes 821590Srgrimes if (!annoType.isAnnotation()) 831590Srgrimes throw new IllegalArgumentException("Not an annotation type: " 84155875Scognet + annoType); 85200156Sed // If annoType does not declare a container this is equivalent to wrapping 86155875Scognet // getAnnotation(...) in an array. 87155875Scognet Class <? extends Annotation> containerType = getContainer(annoType); 88155875Scognet if (containerType == null) { 89155875Scognet A res = getAnnotation(annoType); 90200156Sed int size = res == null ? 0 : 1; 91155875Scognet 92155875Scognet @SuppressWarnings("unchecked") // annoType is the Class for A 93155875Scognet A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 94155875Scognet if (res != null) 95155875Scognet arr[0] = res; 96155875Scognet return arr; 971590Srgrimes } 9873255Simp 991590Srgrimes // So we have a containing type 1001590Srgrimes String annoTypeName = annoType.getName(); 101200156Sed String containerTypeName = containerType.getName(); 10273255Simp int directIndex = -1, containerIndex = -1; 10383082Sru Attribute.Compound direct = null, container = null; 10473255Simp // Find directly (explicit or implicit) present annotations 10573255Simp int index = -1; 10683242Sdd for (Attribute.Compound attribute : getAnnotationMirrors()) { 10783242Sdd index++; 10873255Simp if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) { 1091590Srgrimes directIndex = index; 11025777Sache direct = attribute; 11125777Sache } else if(containerTypeName != null && 11273255Simp attribute.type.tsym.flatName().contentEquals(containerTypeName)) { 1131590Srgrimes containerIndex = index; 1141590Srgrimes container = attribute; 1151590Srgrimes } 1161590Srgrimes } 1171590Srgrimes 1181590Srgrimes // Deal with inherited annotations 11973255Simp if (direct == null && container == null && 12073255Simp annoType.isAnnotationPresent(Inherited.class)) 12173255Simp return getInheritedAnnotations(annoType); 12273255Simp 12373255Simp Attribute.Compound[] contained = unpackContained(container); 12473255Simp 12573255Simp // In case of an empty legacy container we might need to look for 1261590Srgrimes // inherited annos as well 1271590Srgrimes if (direct == null && contained.length == 0 && 12828695Scharnier annoType.isAnnotationPresent(Inherited.class)) 1291590Srgrimes return getInheritedAnnotations(annoType); 1301590Srgrimes 1311590Srgrimes int size = (direct == null ? 0 : 1) + contained.length; 1321590Srgrimes @SuppressWarnings("unchecked") // annoType is the Class for A 13328695Scharnier A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size); 1341590Srgrimes 13573255Simp // if direct && container, which is first? 13673255Simp int insert = -1; 13773320Simp int length = arr.length; 13873255Simp if (directIndex >= 0 && containerIndex >= 0) { 13973320Simp if (directIndex < containerIndex) { 14073320Simp arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 14173255Simp insert = 1; 14273255Simp } else { 1431590Srgrimes arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 1441590Srgrimes insert = 0; 1451590Srgrimes length--; 1461590Srgrimes } 1471590Srgrimes } else if (directIndex >= 0) { 148200156Sed arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType); 149200156Sed return arr; 1501590Srgrimes } else { 151200156Sed // Only container 152155875Scognet insert = 0; 15373255Simp } 15483082Sru 155200156Sed for (int i = 0; i + insert < length; i++) 15673255Simp arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType); 15773255Simp 15873255Simp return arr; 15987675Smarkm } 16073255Simp 16173255Simp private Attribute.Compound[] unpackContained(Attribute.Compound container) { 16273255Simp // Pack them in an array 16383082Sru Attribute[] contained0 = null; 16483082Sru if (container != null) 165200156Sed contained0 = unpackAttributes(container); 16683082Sru ListBuffer<Attribute.Compound> compounds = new ListBuffer<>(); 16783082Sru if (contained0 != null) { 16883082Sru for (Attribute a : contained0) 16983082Sru if (a instanceof Attribute.Compound) 17083082Sru compounds = compounds.append((Attribute.Compound)a); 17173255Simp } 17273255Simp return compounds.toArray(new Attribute.Compound[compounds.size()]); 17373255Simp } 17473255Simp 175200156Sed // This method is part of the javax.lang.model API, do not use this in javac code. 17628695Scharnier @DefinedBy(Api.LANGUAGE_MODEL) 1771590Srgrimes public <A extends Annotation> A getAnnotation(Class<A> annoType) { 1781590Srgrimes 1791590Srgrimes if (!annoType.isAnnotation()) 1801590Srgrimes throw new IllegalArgumentException("Not an annotation type: " + annoType); 18128695Scharnier 182201224Sed Attribute.Compound c = getAttribute(annoType); 18328695Scharnier return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType); 18473320Simp } 18528695Scharnier 18628695Scharnier // Needed to unpack the runtime view of containing annotations 18728695Scharnier private static final Class<? extends Annotation> REPEATABLE_CLASS = initRepeatable(); 1881590Srgrimes private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod(); 18973255Simp 1901590Srgrimes private static Class<? extends Annotation> initRepeatable() { 19173255Simp try { 19273255Simp // Repeatable will not be available when bootstrapping on 1931590Srgrimes // JDK 7 so use a reflective lookup instead of a class 1941590Srgrimes // literal for Repeatable.class. 1951590Srgrimes return Class.forName("java.lang.annotation.Repeatable").asSubclass(Annotation.class); 19629434Sache } catch (ClassNotFoundException | SecurityException e) { 1971590Srgrimes return null; 1981590Srgrimes } 19987675Smarkm } 20087675Smarkm 20169231Skris private static Method initValueElementMethod() { 20276367Skris if (REPEATABLE_CLASS == null) 2031590Srgrimes return null; 20469231Skris 20569231Skris Method m = null; 20669231Skris try { 2071590Srgrimes m = REPEATABLE_CLASS.getMethod("value"); 2081590Srgrimes if (m != null) 2091590Srgrimes m.setAccessible(true); 21069231Skris return m; 21169231Skris } catch (NoSuchMethodException e) { 21266557Sn_hibma return null; 21366557Sn_hibma } 2141590Srgrimes } 2151590Srgrimes 2161590Srgrimes 2171590Srgrimes // Helper to getAnnotationsByType 2181590Srgrimes private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) { 2191590Srgrimes // Since we can not refer to java.lang.annotation.Repeatable until we are 2201590Srgrimes // bootstrapping with java 8 we need to get the Repeatable annotation using 2211590Srgrimes // reflective invocations instead of just using its type and element method. 2221590Srgrimes if (REPEATABLE_CLASS != null && 2231590Srgrimes VALUE_ELEMENT_METHOD != null) { 2241590Srgrimes // Get the Repeatable instance on the annotations declaration 2251590Srgrimes Annotation repeatable = (Annotation)annoType.getAnnotation(REPEATABLE_CLASS); 2261590Srgrimes if (repeatable != null) { 2271590Srgrimes try { 22841717Sdillon // Get the value element, it should be a class 22941717Sdillon // indicating the containing annotation type 2301590Srgrimes @SuppressWarnings("unchecked") 2311590Srgrimes Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(repeatable); 23269231Skris if (containerType == null) 23366557Sn_hibma return null; 23463909Sasmodai 2351590Srgrimes return containerType; 2361590Srgrimes } catch (ClassCastException | IllegalAccessException | InvocationTargetException e) { 2371590Srgrimes return null; 2381590Srgrimes } 23976367Skris } 24076367Skris } 24176367Skris return null; 24276367Skris } 24376367Skris 24476367Skris 24576367Skris // Helper to getAnnotationsByType 246175346Sdas private static Attribute[] unpackAttributes(Attribute.Compound container) { 2471590Srgrimes // We now have an instance of the container, 24850776Sdbaker // unpack it returning an instance of the 249175346Sdas // contained type or null 25050776Sdbaker return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values; 251175346Sdas } 252175346Sdas 2531590Srgrimes} 2541590Srgrimes