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 for {@link AnnotatedElement#getDeclaredAnnotation}. 36 * 37 * @return Directly present annotation of type {@code annotationClass} for {@code element}, 38 * or {@code null} if none was found. 39 */ getDeclaredAnnotation(AnnotatedElement element, Class<T> annotationClass)40 public static <T extends Annotation> T getDeclaredAnnotation(AnnotatedElement element, 41 Class<T> annotationClass) { 42 if (annotationClass == null) { 43 throw new NullPointerException("annotationClass"); 44 } 45 46 Annotation[] annotations = element.getDeclaredAnnotations(); 47 48 // Safeguard: getDeclaredAnnotations should never return null. 49 if (annotations == null) { 50 return null; 51 } 52 53 // The annotation might be directly present: 54 // Return the first (and only) annotation whose class matches annotationClass. 55 for (int i = 0; i < annotations.length; ++i) { 56 if (annotationClass.isInstance(annotations[i])) { 57 return (T)annotations[i]; // Safe because of above guard. 58 } 59 } 60 61 // The annotation was *not* directly present: 62 // If the array was empty, or we found no matches, return null. 63 return null; 64 } 65 66 /** 67 * Default implementation for {@link AnnotatedElement#getDeclaredAnnotationsByType}. 68 * 69 * @return Directly/indirectly present list of annotations of type {@code annotationClass} for 70 * {@code element}, or an empty array if none were found. 71 */ getDeclaredAnnotationsByType(AnnotatedElement element, Class<T> annotationClass)72 public static <T extends Annotation> T[] getDeclaredAnnotationsByType(AnnotatedElement element, 73 Class<T> annotationClass) { 74 if (annotationClass == null) { 75 throw new NullPointerException("annotationClass"); 76 } 77 78 Annotation[] annotations = element.getDeclaredAnnotations(); 79 80 // Store a list of repeatable annotations that have been extracted from their container. 81 ArrayList<T> unfoldedAnnotations = new ArrayList<T>(); 82 83 Class<? extends Annotation> repeatableAnnotationClass = 84 getRepeatableAnnotationContainerClassFor(annotationClass); 85 86 for (int i = 0; i < annotations.length; ++i) { 87 if (annotationClass.isInstance(annotations[i])) { 88 // Is it directly present? 89 unfoldedAnnotations.add((T)annotations[i]); // Safe, guarded by above check. 90 } else if (repeatableAnnotationClass != null && 91 repeatableAnnotationClass.isInstance(annotations[i])) { 92 // Is it repeatably (indirectly) present? 93 insertAnnotationValues(annotations[i], annotationClass, unfoldedAnnotations); 94 } 95 } 96 97 return unfoldedAnnotations.toArray((T[])Array.newInstance(annotationClass, 0)); 98 } 99 100 /** 101 * Extracts annotations from a container annotation and inserts them into a list. 102 * 103 * <p> 104 * Given a complex annotation "annotation", it should have a "T[] value()" method on it. 105 * Call that method and add all of the nested annotations into unfoldedAnnotations list. 106 * </p> 107 */ insertAnnotationValues(Annotation annotation, Class<T> annotationClass, ArrayList<T> unfoldedAnnotations)108 private static <T extends Annotation> void insertAnnotationValues(Annotation annotation, 109 Class<T> annotationClass, ArrayList<T> unfoldedAnnotations) { 110 // annotation is a complex annotation which has elements of instance annotationClass 111 // (whose static type is T). 112 // 113 // @interface SomeName { <--- = annotation.getClass() 114 // ... 115 // T[] value(); <--- T.class == annotationClass 116 // } 117 // 118 // Use reflection to access these values. 119 Class<T[]> annotationArrayClass = 120 (Class<T[]>)((T[])Array.newInstance(annotationClass, 0)).getClass(); 121 122 Method valuesMethod; 123 try { 124 valuesMethod = annotation.getClass().getDeclaredMethod("value"); 125 // This will always succeed unless the annotation and its repeatable annotation class were 126 // recompiled separately, then this is a binary incompatibility error. 127 } catch (NoSuchMethodException e) { 128 throw new AssertionError("annotation container = " + annotation + 129 "annotation element class = " + annotationClass + "; missing value() method"); 130 } catch (SecurityException e) { 131 throw new IncompleteAnnotationException(annotation.getClass(), "value"); 132 } 133 134 // Ensure that value() returns a T[] 135 if (!valuesMethod.getReturnType().isArray()) { 136 throw new AssertionError("annotation container = " + annotation + 137 "annotation element class = " + annotationClass + "; value() doesn't return array"); 138 } 139 140 // Ensure that the T[] value() is actually the correct type (T==annotationClass). 141 if (!annotationClass.equals(valuesMethod.getReturnType().getComponentType())) { 142 throw new AssertionError("annotation container = " + annotation + 143 "annotation element class = " + annotationClass + "; value() returns incorrect type"); 144 } 145 146 // Append those values into the existing list. 147 T[] nestedAnnotations; 148 try { 149 nestedAnnotations = (T[])valuesMethod.invoke(annotation); // Safe because of #getMethod. 150 } catch (IllegalAccessException|InvocationTargetException e) { 151 throw new AssertionError(e); 152 } 153 154 for (int i = 0; i < nestedAnnotations.length; ++i) { 155 unfoldedAnnotations.add(nestedAnnotations[i]); 156 } 157 } 158 159 /** 160 * Find the {@code \@Repeatable} container annotation class for an annotation class, or 161 * {@code null}. 162 * 163 * <p> 164 * Given: 165 * 166 * <code> 167 * @Repeatable(X.class) 168 * @interface SomeName { <--- = annotationClass 169 * }... 170 * </code> 171 * 172 * <p> 173 * Returns {@code X.class} 174 * 175 * Otherwise if there was no {@code \@Repeatable} annotation, return {@code null}. 176 * </p> 177 */ 178 private static <T extends Annotation> Class<? extends Annotation> getRepeatableAnnotationContainerClassFor(Class<T> annotationClass)179 getRepeatableAnnotationContainerClassFor(Class<T> annotationClass) { 180 181 Repeatable repeatableAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class); 182 return (repeatableAnnotation == null) ? null : repeatableAnnotation.value(); 183 } 184 185 /** 186 * Default implementation of {@link AnnotatedElement#getAnnotationsByType}. 187 * 188 * <p> 189 * This method does not handle inherited annotations and is 190 * intended for use for {@code Method}, {@code Field}, {@code Package}. 191 * The {@link Class#getAnnotationsByType} is implemented explicitly. 192 * </p> 193 * 194 * @return Associated annotations of type {@code annotationClass} for {@code element}. 195 */ getAnnotationsByType(AnnotatedElement element, Class<T> annotationClass)196 public static <T extends Annotation> T[] getAnnotationsByType(AnnotatedElement element, 197 Class<T> annotationClass) { 198 if (annotationClass == null) { 199 throw new NullPointerException("annotationClass"); 200 } 201 202 // Find any associated annotations [directly or repeatably (indirectly) present on this class]. 203 T[] annotations = element.getDeclaredAnnotationsByType(annotationClass); 204 if (annotations == null) { 205 throw new AssertionError("annotations must not be null"); // Internal error. 206 } 207 208 // If nothing was found, we would look for associated annotations recursively up to the root 209 // class. However this can only happen if AnnotatedElement is a Class, which is handled 210 // in the Class override of this method. 211 return annotations; 212 } 213 AnnotatedElements()214 private AnnotatedElements() { 215 throw new AssertionError("Instances of AnnotatedElements not allowed"); 216 } 217 } 218 219