Mon, 23 Sep 2013 10:42:38 +0200
6386236: Please rename com.sun.tools.javac.util.ListBuffer.lb()
Summary: Static factory method ListBuffer.lb removed. Replaced by constructor calls.
Reviewed-by: jfranck, jjg
1 /*
2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.javac.model;
27 import java.lang.annotation.Annotation;
28 import java.lang.annotation.Inherited;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
32 import com.sun.tools.javac.code.Attribute;
33 import com.sun.tools.javac.code.Kinds;
34 import com.sun.tools.javac.code.Symbol;
35 import com.sun.tools.javac.code.Symbol.ClassSymbol;
36 import com.sun.tools.javac.code.Symbol.TypeVariableSymbol;
37 import com.sun.tools.javac.code.TargetType;
38 import com.sun.tools.javac.code.Type;
39 import com.sun.tools.javac.code.Type.AnnotatedType;
40 import com.sun.tools.javac.util.ListBuffer;
41 import static com.sun.tools.javac.code.TypeTag.CLASS;
42 import com.sun.tools.javac.util.List;
44 /**
45 * Utility methods for operating on annotated constructs.
46 *
47 * <p><b>This is NOT part of any supported API.
48 * If you write code that depends on this, you do so at your own
49 * risk. This code and its internal interfaces are subject to change
50 * or deletion without notice.</b></p>
51 */
52 public class JavacAnnoConstructs {
54 // <editor-fold defaultstate="collapsed" desc="Symbols">
56 /**
57 * An internal-use utility that creates a runtime view of an
58 * annotation. This is the implementation of
59 * Element.getAnnotation(Class).
60 */
61 public static <A extends Annotation> A getAnnotation(Symbol annotated,
62 Class<A> annoType) {
63 if (!annoType.isAnnotation())
64 throw new IllegalArgumentException("Not an annotation type: "
65 + annoType);
66 Attribute.Compound c;
67 if (annotated.kind == Kinds.TYP &&
68 annotated instanceof ClassSymbol) {
69 c = getAttributeOnClass((ClassSymbol)annotated, annoType);
70 } else if (annotated.kind == Kinds.TYP &&
71 annotated instanceof TypeVariableSymbol) {
72 c = getAttributeOnTypeVariable((TypeVariableSymbol)annotated, annoType);
73 } else {
74 c = getAttribute(annotated, annoType);
75 }
76 return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType);
77 }
79 // Helper to getAnnotation[s]
80 private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated,
81 Class<A> annoType) {
82 String name = annoType.getName();
84 for (Attribute.Compound anno : annotated.getRawAttributes()) {
85 if (name.equals(anno.type.tsym.flatName().toString()))
86 return anno;
87 }
89 return null;
90 }
92 // Helper to getAnnotation[s]
93 private static <A extends Annotation> Attribute.Compound
94 getAttributeOnTypeVariable(TypeVariableSymbol annotated, Class<A> annoType) {
95 String name = annoType.getName();
97 // Declaration annotations on type variables are stored in type attributes
98 // on the owner of the TypeVariableSymbol
99 List<Attribute.Compound> res = List.nil();
100 List<Attribute.TypeCompound> candidates = annotated.owner.getRawTypeAttributes();
101 for (Attribute.TypeCompound anno : candidates)
102 if (anno.position.type == TargetType.CLASS_TYPE_PARAMETER ||
103 anno.position.type == TargetType.METHOD_TYPE_PARAMETER)
104 if (name.equals(anno.type.tsym.flatName().toString()))
105 return anno;
107 return null;
108 }
110 // Helper to getAnnotation[s]
111 private static <A extends Annotation> Attribute.Compound getAttributeOnClass(
112 ClassSymbol annotated,
113 final Class<A> annoType)
114 {
115 boolean inherited = annoType.isAnnotationPresent(Inherited.class);
116 Attribute.Compound result = null;
118 result = getAttribute(annotated, annoType);
119 if (result != null || !inherited)
120 return result;
122 while ((annotated = nextSupertypeToSearch(annotated)) != null) {
123 result = getAttribute(annotated, annoType);
124 if (result != null)
125 return result;
126 }
127 return null; // no more supertypes to search
128 }
130 /**
131 * Returns the next type to search for inherited annotations or {@code null}
132 * if the next type can't be found.
133 */
134 private static ClassSymbol nextSupertypeToSearch(ClassSymbol annotated) {
135 if (annotated.name == annotated.name.table.names.java_lang_Object)
136 return null;
138 Type sup = annotated.getSuperclass();
139 if (!sup.hasTag(CLASS) || sup.isErroneous())
140 return null;
142 return (ClassSymbol) sup.tsym;
143 }
145 /**
146 * An internal-use utility that creates a runtime view of
147 * annotations. This is the implementation of
148 * Element.getAnnotations(Class).
149 */
150 public static <A extends Annotation> A[] getAnnotationsByType(Symbol annotated,
151 Class<A> annoType)
152 {
153 if (!annoType.isAnnotation())
154 throw new IllegalArgumentException("Not an annotation type: "
155 + annoType);
156 // If annoType does not declare a container this is equivalent to wrapping
157 // getAnnotation(...) in an array.
158 Class <? extends Annotation> containerType = getContainer(annoType);
159 if (containerType == null) {
160 A res = getAnnotation(annotated, annoType);
161 int size;
162 if (res == null) {
163 size = 0;
164 } else {
165 size = 1;
166 }
167 @SuppressWarnings("unchecked") // annoType is the Class for A
168 A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
169 if (res != null)
170 arr[0] = res;
171 return arr;
172 }
174 // So we have a containing type
175 String annoTypeName = annoType.getName();
176 String containerTypeName = containerType.getName();
177 int directIndex = -1, containerIndex = -1;
178 Attribute.Compound direct = null, container = null;
179 // Find directly (explicit or implicit) present annotations
180 int index = -1;
181 for (List<Attribute.Compound> list = annotated.getAnnotationMirrors();
182 !list.isEmpty();
183 list = list.tail) {
184 Attribute.Compound attribute = list.head;
185 index++;
186 if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) {
187 directIndex = index;
188 direct = attribute;
189 } else if(containerTypeName != null &&
190 attribute.type.tsym.flatName().contentEquals(containerTypeName)) {
191 containerIndex = index;
192 container = attribute;
193 }
194 }
196 // Deal with inherited annotations
197 if (direct == null && container == null) {
198 if (annotated.kind == Kinds.TYP &&
199 (annotated instanceof ClassSymbol)) {
200 ClassSymbol s = nextSupertypeToSearch((ClassSymbol)annotated);
201 if (s != null)
202 return getAnnotationsByType(s, annoType);
203 }
204 }
206 // Pack them in an array
207 Attribute[] contained0 = null;
208 if (container != null)
209 contained0 = unpackAttributes(container);
210 ListBuffer<Attribute.Compound> compounds = new ListBuffer<>();
211 if (contained0 != null) {
212 for (Attribute a : contained0)
213 if (a instanceof Attribute.Compound)
214 compounds = compounds.append((Attribute.Compound)a);
215 }
216 Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[compounds.size()]);
218 int size = (direct == null ? 0 : 1) + contained.length;
219 @SuppressWarnings("unchecked") // annoType is the Class for A
220 A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
222 // if direct && container, which is first?
223 int insert = -1;
224 int length = arr.length;
225 if (directIndex >= 0 && containerIndex >= 0) {
226 if (directIndex < containerIndex) {
227 arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
228 insert = 1;
229 } else {
230 arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
231 insert = 0;
232 length--;
233 }
234 } else if (directIndex >= 0) {
235 arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
236 return arr;
237 } else {
238 // Only container
239 insert = 0;
240 }
242 for (int i = 0; i + insert < length; i++)
243 arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType);
245 return arr;
246 }
248 // </editor-fold>
250 // <editor-fold defaultstate="collapsed" desc="Types">
252 /**
253 * An internal-use utility that creates a runtime view of an
254 * annotation. This is the implementation of
255 * TypeMirror.getAnnotation(Class).
256 */
257 public static <A extends Annotation> A getAnnotation(AnnotatedType annotated, Class<A> annoType) {
258 if (!annoType.isAnnotation())
259 throw new IllegalArgumentException("Not an annotation type: "
260 + annoType);
261 Attribute.Compound c = getAttribute(annotated, annoType);
262 return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType);
263 }
265 // Helper to getAnnotation[s]
266 private static <A extends Annotation> Attribute.Compound getAttribute(Type annotated,
267 Class<A> annoType) {
268 String name = annoType.getName();
270 for (Attribute.Compound anno : annotated.getAnnotationMirrors()) {
271 if (name.equals(anno.type.tsym.flatName().toString()))
272 return anno;
273 }
275 return null;
276 }
278 /**
279 * An internal-use utility that creates a runtime view of
280 * annotations. This is the implementation of
281 * TypeMirror.getAnnotationsByType(Class).
282 */
283 public static <A extends Annotation> A[] getAnnotationsByType(AnnotatedType annotated, Class<A> annoType) {
284 if (!annoType.isAnnotation())
285 throw new IllegalArgumentException("Not an annotation type: "
286 + annoType);
287 // If annoType does not declare a container this is equivalent to wrapping
288 // getAnnotation(...) in an array.
289 Class <? extends Annotation> containerType = getContainer(annoType);
290 if (containerType == null) {
291 A res = getAnnotation(annotated, annoType);
292 int size;
293 if (res == null) {
294 size = 0;
295 } else {
296 size = 1;
297 }
298 @SuppressWarnings("unchecked") // annoType is the Class for A
299 A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
300 if (res != null)
301 arr[0] = res;
302 return arr;
303 }
305 // So we have a containing type
306 String annoTypeName = annoType.getName();
307 String containerTypeName = containerType.getName();
308 int directIndex = -1, containerIndex = -1;
309 Attribute.Compound direct = null, container = null;
310 // Find directly (explicit or implicit) present annotations
311 int index = -1;
312 for (List<? extends Attribute.Compound> list = annotated.getAnnotationMirrors();
313 !list.isEmpty();
314 list = list.tail) {
315 Attribute.Compound attribute = list.head;
316 index++;
317 if (attribute.type.tsym.flatName().contentEquals(annoTypeName)) {
318 directIndex = index;
319 direct = attribute;
320 } else if(containerTypeName != null &&
321 attribute.type.tsym.flatName().contentEquals(containerTypeName)) {
322 containerIndex = index;
323 container = attribute;
324 }
325 }
327 // Pack them in an array
328 Attribute[] contained0 = null;
329 if (container != null)
330 contained0 = unpackAttributes(container);
331 ListBuffer<Attribute.Compound> compounds = new ListBuffer<>();
332 if (contained0 != null) {
333 for (Attribute a : contained0)
334 if (a instanceof Attribute.Compound)
335 compounds = compounds.append((Attribute.Compound)a);
336 }
337 Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[compounds.size()]);
339 int size = (direct == null ? 0 : 1) + contained.length;
340 @SuppressWarnings("unchecked") // annoType is the Class for A
341 A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
343 // if direct && container, which is first?
344 int insert = -1;
345 int length = arr.length;
346 if (directIndex >= 0 && containerIndex >= 0) {
347 if (directIndex < containerIndex) {
348 arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
349 insert = 1;
350 } else {
351 arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
352 insert = 0;
353 length--;
354 }
355 } else if (directIndex >= 0) {
356 arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
357 return arr;
358 } else {
359 // Only container
360 insert = 0;
361 }
363 for (int i = 0; i + insert < length; i++)
364 arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType);
366 return arr;
367 }
369 // </editor-fold>
371 // <editor-fold defaultstate="collapsed" desc="Container support">
373 // Needed to unpack the runtime view of containing annotations
374 private static final Class<? extends Annotation> REPEATABLE_CLASS = initRepeatable();
375 private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod();
377 private static Class<? extends Annotation> initRepeatable() {
378 try {
379 // Repeatable will not be available when bootstrapping on
380 // JDK 7 so use a reflective lookup instead of a class
381 // literal for Repeatable.class.
382 return Class.forName("java.lang.annotation.Repeatable").asSubclass(Annotation.class);
383 } catch (ClassNotFoundException e) {
384 return null;
385 } catch (SecurityException e) {
386 return null;
387 }
388 }
390 private static Method initValueElementMethod() {
391 if (REPEATABLE_CLASS == null)
392 return null;
394 Method m = null;
395 try {
396 m = REPEATABLE_CLASS.getMethod("value");
397 if (m != null)
398 m.setAccessible(true);
399 return m;
400 } catch (NoSuchMethodException e) {
401 return null;
402 }
403 }
405 // Helper to getAnnotations
406 private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) {
407 // Since we can not refer to java.lang.annotation.Repeatable until we are
408 // bootstrapping with java 8 we need to get the Repeatable annotation using
409 // reflective invocations instead of just using its type and element method.
410 if (REPEATABLE_CLASS != null &&
411 VALUE_ELEMENT_METHOD != null) {
412 // Get the Repeatable instance on the annotations declaration
413 Annotation repeatable = (Annotation)annoType.getAnnotation(REPEATABLE_CLASS);
414 if (repeatable != null) {
415 try {
416 // Get the value element, it should be a class
417 // indicating the containing annotation type
418 @SuppressWarnings("unchecked")
419 Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(repeatable);
420 if (containerType == null)
421 return null;
423 return containerType;
424 } catch (ClassCastException e) {
425 return null;
426 } catch (IllegalAccessException e) {
427 return null;
428 } catch (InvocationTargetException e ) {
429 return null;
430 }
431 }
432 }
433 return null;
434 }
436 // Helper to getAnnotations
437 private static Attribute[] unpackAttributes(Attribute.Compound container) {
438 // We now have an instance of the container,
439 // unpack it returning an instance of the
440 // contained type or null
441 return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values;
442 }
444 // </editor-fold>
445 }