1 /* 2 * Copyright (C) 2018 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 import java.lang.annotation.Annotation; 18 import java.lang.annotation.Retention; 19 import java.lang.annotation.RetentionPolicy; 20 import java.lang.reflect.Constructor; 21 import java.lang.reflect.Parameter; 22 23 public class Main { 24 // A simple parameter annotation 25 @Retention(RetentionPolicy.RUNTIME) 26 public @interface AnnotationA {} 27 28 // A parameter annotation with additional state 29 @Retention(RetentionPolicy.RUNTIME) 30 public @interface AnnotationB { value()31 String value() default "default-value"; 32 } 33 34 // An inner class whose constructors with have an implicit 35 // argument for the enclosing instance. 36 public class Inner { 37 private final int number; 38 private final String text; 39 boolean flag; 40 Inner(@nnotationA int number, String text)41 Inner(@AnnotationA int number, String text) { 42 this.number = number; 43 this.text = text; 44 this.flag = false; 45 } 46 Inner(@nnotationA int number, String text, @AnnotationB("x") boolean flag)47 Inner(@AnnotationA int number, String text, @AnnotationB("x") boolean flag) { 48 this.number = number; 49 this.text = text; 50 this.flag = flag; 51 } 52 } 53 54 // An inner class whose constructors with have no implicit 55 // arguments for the enclosing instance. 56 public static class StaticInner { 57 private final int number; 58 private final String text; 59 boolean flag; 60 StaticInner(@nnotationA int number, String text)61 StaticInner(@AnnotationA int number, String text) { 62 this.number = number; 63 this.text = text; 64 this.flag = false; 65 } 66 StaticInner(@nnotationB"foo") int number, String text, @AnnotationA boolean flag)67 StaticInner(@AnnotationB("foo") int number, String text, @AnnotationA boolean flag) { 68 this.number = number; 69 this.text = text; 70 this.flag = flag; 71 } 72 } 73 74 public enum ImportantNumber { 75 ONE(1.0), 76 TWO(2.0), 77 MANY(3.0, true); 78 79 private double doubleValue; 80 private boolean isLarge; 81 ImportantNumber(@nnotationA double doubleValue)82 ImportantNumber(@AnnotationA double doubleValue) { 83 this.doubleValue = doubleValue; 84 this.isLarge = false; 85 } 86 ImportantNumber(@nnotationB"x") double doubleValue, @AnnotationB("y") boolean isLarge)87 ImportantNumber(@AnnotationB("x") double doubleValue, @AnnotationB("y") boolean isLarge) { 88 this.doubleValue = doubleValue; 89 this.isLarge = isLarge; 90 } 91 } 92 93 public enum BinaryNumber { 94 ZERO, 95 ONE; 96 } 97 98 private abstract static class AnonymousBase { AnonymousBase(@nnotationA String s)99 public AnonymousBase(@AnnotationA String s) {} 100 } 101 annotationToNormalizedString(Annotation annotation)102 private static String annotationToNormalizedString(Annotation annotation) { 103 // String.replace() to accomodate different representation across VMs. 104 return annotation.toString().replace("\"", ""); 105 } 106 DumpConstructorParameterAnnotations(Class<?> cls)107 private static void DumpConstructorParameterAnnotations(Class<?> cls) throws Throwable { 108 System.out.println(cls.getName()); 109 for (Constructor c : cls.getDeclaredConstructors()) { 110 System.out.println(" " + c); 111 Annotation[][] annotations = c.getParameterAnnotations(); 112 Parameter[] parameters = c.getParameters(); 113 for (int i = 0; i < annotations.length; ++i) { 114 // Exercise java.lang.reflect.Executable.getParameterAnnotationsNative() 115 // which retrieves all annotations for the parameters. 116 System.out.print(" Parameter [" + i + "]:"); 117 for (Annotation annotation : parameters[i].getAnnotations()) { 118 System.out.println(" Indexed : " + annotationToNormalizedString(annotation)); 119 } 120 for (Annotation annotation : annotations[i]) { 121 System.out.println(" Array : " + annotationToNormalizedString(annotation)); 122 } 123 124 // Exercise Parameter.getAnnotationNative() with 125 // retrieves a single parameter annotation according to type. 126 Object[] opaqueClasses = new Object[] {AnnotationA.class, AnnotationB.class}; 127 for (Object opaqueClass : opaqueClasses) { 128 @SuppressWarnings("unchecked") 129 Class<? extends Annotation> annotationClass = 130 (Class<? extends Annotation>) opaqueClass; 131 Annotation annotation = parameters[i].getDeclaredAnnotation(annotationClass); 132 String hasAnnotation = (annotation != null ? "Yes" : "No"); 133 System.out.println(" " + annotationClass.getName() + " " + hasAnnotation); 134 135 Annotation[] parameterAnnotations = parameters[i].getDeclaredAnnotationsByType(annotationClass); 136 for (Annotation parameterAnnotation : parameterAnnotations) { 137 System.out.println(" " + annotationToNormalizedString(parameterAnnotation)); 138 } 139 } 140 } 141 } 142 } 143 getLocalClassWithEnclosingInstanceCapture()144 private Class<?> getLocalClassWithEnclosingInstanceCapture() { 145 class LocalClass { 146 private final int integerValue; 147 148 LocalClass(@AnnotationA int integerValue) { 149 this.integerValue = integerValue; 150 } 151 } 152 return LocalClass.class; 153 } 154 getLocalClassWithEnclosingInstanceAndLocalCapture()155 private Class<?> getLocalClassWithEnclosingInstanceAndLocalCapture() { 156 final long CAPTURED_VALUE = System.currentTimeMillis(); 157 class LocalClassWithCapture { 158 private final String value; 159 private final long capturedValue; 160 161 LocalClassWithCapture(@AnnotationA String p1) { 162 this.value = p1; 163 this.capturedValue = CAPTURED_VALUE; 164 } 165 } 166 return LocalClassWithCapture.class; 167 } 168 main(String[] args)169 public static void main(String[] args) throws Throwable { 170 // A local class declared in a static context (0 implicit parameters). 171 class LocalClassStaticContext { 172 private final int value; 173 174 LocalClassStaticContext(@AnnotationA int p0) { 175 this.value = p0; 176 } 177 } 178 179 final long CAPTURED_VALUE = System.currentTimeMillis(); 180 // A local class declared in a static context with a capture (1 implicit parameters). 181 class LocalClassStaticContextWithCapture { 182 private final long capturedValue; 183 private final String argumentValue; 184 185 LocalClassStaticContextWithCapture(@AnnotationA String p1) { 186 this.capturedValue = CAPTURED_VALUE; 187 this.argumentValue = p1; 188 } 189 } 190 191 // Another local class declared in a static context with a capture (1 implicit parameters). 192 class LocalClassStaticContextWithCaptureAlternateOrdering { 193 private final String argumentValue; 194 private final long capturedValue; 195 196 LocalClassStaticContextWithCaptureAlternateOrdering(@AnnotationA String p1) { 197 this.argumentValue = p1; 198 this.capturedValue = CAPTURED_VALUE; 199 } 200 } 201 202 DumpConstructorParameterAnnotations(Main.class); 203 DumpConstructorParameterAnnotations(LocalClassStaticContext.class); 204 DumpConstructorParameterAnnotations(LocalClassStaticContextWithCapture.class); 205 DumpConstructorParameterAnnotations(LocalClassStaticContextWithCaptureAlternateOrdering.class); 206 Main m = new Main(); 207 DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceCapture()); 208 DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceAndLocalCapture()); 209 DumpConstructorParameterAnnotations(Inner.class); 210 DumpConstructorParameterAnnotations(StaticInner.class); 211 DumpConstructorParameterAnnotations(ImportantNumber.class); 212 DumpConstructorParameterAnnotations(BinaryNumber.class); 213 DumpConstructorParameterAnnotations(new AnonymousBase("") {}.getClass()); 214 } 215 } 216