1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.reflect; 18 19 import java.lang.annotation.Annotation; 20 import java.lang.annotation.IncompleteAnnotationException; 21 import java.lang.annotation.Repeatable; 22 import java.lang.reflect.*; 23 import java.util.ArrayList; 24 25 /** 26 * Implementation of {@link AnnotatedElement}'s 1.8 methods. 27 * 28 * <p>This implementation is shared between all the classes implementing {@link AnnotatedElement}, 29 * avoiding code duplication.</p> 30 * 31 * @hide 32 */ 33 public final class AnnotatedElements { 34 /** 35 * Default implementation of {@link AnnotatedElement#getDeclaredAnnotationsByType}, and 36 * {@link AnnotatedElement#getAnnotationsByType} for elements that do not support annotation 37 * inheritance. 38 * 39 * @return Directly/indirectly present list of annotations of type {@code annotationClass} for 40 * {@code element}, or an empty array if none were found. 41 */ getDirectOrIndirectAnnotationsByType( AnnotatedElement element, Class<T> annotationClass)42 public static <T extends Annotation> T[] getDirectOrIndirectAnnotationsByType( 43 AnnotatedElement element, Class<T> annotationClass) { 44 if (annotationClass == null) { 45 throw new NullPointerException("annotationClass"); 46 } 47 48 Annotation[] annotations = element.getDeclaredAnnotations(); 49 50 // Store a list of repeatable annotations that have been extracted from their container. 51 ArrayList<T> unfoldedAnnotations = new ArrayList<T>(); 52 53 Class<? extends Annotation> repeatableAnnotationClass = 54 getRepeatableAnnotationContainerClassFor(annotationClass); 55 56 for (int i = 0; i < annotations.length; ++i) { 57 if (annotationClass.isInstance(annotations[i])) { 58 // Is it directly present? 59 unfoldedAnnotations.add((T)annotations[i]); // Safe, guarded by above check. 60 } else if (repeatableAnnotationClass != null && 61 repeatableAnnotationClass.isInstance(annotations[i])) { 62 // Is it repeatably (indirectly) present? 63 insertAnnotationValues(annotations[i], annotationClass, unfoldedAnnotations); 64 } 65 } 66 67 return unfoldedAnnotations.toArray((T[])Array.newInstance(annotationClass, 0)); 68 } 69 70 /** 71 * Extracts annotations from a container annotation and inserts them into a list. 72 * 73 * <p> 74 * Given a complex annotation "annotation", it should have a "T[] value()" method on it. 75 * Call that method and add all of the nested annotations into unfoldedAnnotations list. 76 * </p> 77 */ insertAnnotationValues(Annotation annotation, Class<T> annotationClass, ArrayList<T> unfoldedAnnotations)78 private static <T extends Annotation> void insertAnnotationValues(Annotation annotation, 79 Class<T> annotationClass, ArrayList<T> unfoldedAnnotations) { 80 // annotation is a complex annotation which has elements of instance annotationClass 81 // (whose static type is T). 82 // 83 // @interface SomeName { <--- = annotation.getClass() 84 // ... 85 // T[] value(); <--- T.class == annotationClass 86 // } 87 // 88 // Use reflection to access these values. 89 Class<T[]> annotationArrayClass = 90 (Class<T[]>)((T[])Array.newInstance(annotationClass, 0)).getClass(); 91 92 Method valuesMethod; 93 try { 94 valuesMethod = annotation.getClass().getDeclaredMethod("value"); 95 // This will always succeed unless the annotation and its repeatable annotation class were 96 // recompiled separately, then this is a binary incompatibility error. 97 } catch (NoSuchMethodException e) { 98 throw new AssertionError("annotation container = " + annotation + 99 "annotation element class = " + annotationClass + "; missing value() method"); 100 } catch (SecurityException e) { 101 throw new IncompleteAnnotationException(annotation.getClass(), "value"); 102 } 103 104 // Ensure that value() returns a T[] 105 if (!valuesMethod.getReturnType().isArray()) { 106 throw new AssertionError("annotation container = " + annotation + 107 "annotation element class = " + annotationClass + "; value() doesn't return array"); 108 } 109 110 // Ensure that the T[] value() is actually the correct type (T==annotationClass). 111 if (!annotationClass.equals(valuesMethod.getReturnType().getComponentType())) { 112 throw new AssertionError("annotation container = " + annotation + 113 "annotation element class = " + annotationClass + "; value() returns incorrect type"); 114 } 115 116 // Append those values into the existing list. 117 T[] nestedAnnotations; 118 try { 119 nestedAnnotations = (T[])valuesMethod.invoke(annotation); // Safe because of #getMethod. 120 } catch (IllegalAccessException|InvocationTargetException e) { 121 throw new AssertionError(e); 122 } 123 124 for (int i = 0; i < nestedAnnotations.length; ++i) { 125 unfoldedAnnotations.add(nestedAnnotations[i]); 126 } 127 } 128 129 /** 130 * Find the {@code \@Repeatable} container annotation class for an annotation class, or 131 * {@code null}. 132 * 133 * <p> 134 * Given: 135 * 136 * <code> 137 * @Repeatable(X.class) 138 * @interface SomeName { <--- = annotationClass 139 * }... 140 * </code> 141 * 142 * <p> 143 * Returns {@code X.class} 144 * 145 * Otherwise if there was no {@code \@Repeatable} annotation, return {@code null}. 146 * </p> 147 */ 148 private static <T extends Annotation> Class<? extends Annotation> getRepeatableAnnotationContainerClassFor(Class<T> annotationClass)149 getRepeatableAnnotationContainerClassFor(Class<T> annotationClass) { 150 151 Repeatable repeatableAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class); 152 return (repeatableAnnotation == null) ? null : repeatableAnnotation.value(); 153 } 154 AnnotatedElements()155 private AnnotatedElements() { 156 } 157 } 158 159