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.java.lang.reflect.annotations; 18 19 import junit.framework.TestCase; 20 21 import java.lang.annotation.Annotation; 22 import java.lang.reflect.Constructor; 23 import java.lang.reflect.Executable; 24 import java.lang.reflect.Method; 25 import java.lang.reflect.Parameter; 26 27 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; 28 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; 29 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; 30 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; 31 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; 32 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; 33 34 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; 35 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes; 36 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch; 37 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set; 38 39 /** 40 * Tests for {@link Executable#getParameterAnnotations()} via the {@link Constructor} and 41 * {@link Method} classes. See {@link for testing of the 42 * {@link java.lang.reflect.AnnotatedElement} methods. 43 */ 44 public class ExecutableParameterTest extends TestCase { 45 private static class MethodClass { 46 public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {} 47 48 public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1, 49 @AnnotationC @AnnotationD String parameter2) {} 50 } 51 52 public void testMethodGetParameterAnnotations() throws Exception { 53 Method methodWithoutAnnotatedParameters = MethodClass.class.getMethod( 54 "methodWithoutAnnotatedParameters", String.class, String.class); 55 Annotation[][] noParameterAnnotations = getParameterAnnotations( 56 methodWithoutAnnotatedParameters, 2); 57 assertEquals(set(), annotationsToTypes(noParameterAnnotations[0])); 58 assertEquals(set(), annotationsToTypes(noParameterAnnotations[1])); 59 60 Method methodWithAnnotatedParameters = MethodClass.class.getMethod( 61 "methodWithAnnotatedParameters", String.class, String.class); 62 Annotation[][] parameterAnnotations = getParameterAnnotations( 63 methodWithAnnotatedParameters, 2); 64 assertEquals(set(AnnotationB.class, AnnotationD.class), 65 annotationsToTypes(parameterAnnotations[0])); 66 assertEquals(set(AnnotationC.class, AnnotationD.class), 67 annotationsToTypes(parameterAnnotations[1])); 68 } 69 70 private static class AnnotatedMethodClass { 71 void noAnnotation(String p0) {} 72 73 void multipleAnnotationOddity( 74 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {} 75 76 void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {} 77 78 void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {} 79 80 void singleAnnotation(@Repeated(1) String p0) {} 81 82 static void staticSingleAnnotation(@Repeated(1) String p0) {} 83 84 static Method getMethodWithoutAnnotations() throws Exception { 85 return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class); 86 } 87 88 static Method getMethodMultipleAnnotationOddity() throws Exception { 89 return AnnotatedMethodClass.class.getDeclaredMethod( 90 "multipleAnnotationOddity", String.class); 91 } 92 93 static Method getMethodMultipleAnnotationExplicitSingle() throws Exception { 94 return AnnotatedMethodClass.class.getDeclaredMethod( 95 "multipleAnnotationExplicitSingle", String.class); 96 } 97 98 static Method getMethodMultipleAnnotation() throws Exception { 99 return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class); 100 } 101 102 static Method getMethodSingleAnnotation() throws Exception { 103 return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class); 104 } 105 106 static Method getMethodStaticSingleAnnotation() throws Exception { 107 return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation", 108 String.class); 109 } 110 } 111 112 private static abstract class AnnotatedMethodAbstractClass { 113 abstract void abstractSingleAnnotation(@Repeated(1) String p0); 114 115 static Method getMethodAbstractSingleAnnotation() throws Exception { 116 return AnnotatedMethodAbstractClass.class.getDeclaredMethod( 117 "abstractSingleAnnotation", String.class); 118 } 119 } 120 121 122 public void testMethodGetParameterAnnotations_repeated() throws Exception { 123 assertOnlyParameterAnnotations( 124 AnnotatedMethodClass.getMethodWithoutAnnotations(), EXPECT_EMPTY); 125 assertOnlyParameterAnnotations( 126 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 127 "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})"); 128 assertOnlyParameterAnnotations( 129 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 130 "@Container({@Repeated(1)})"); 131 assertOnlyParameterAnnotations( 132 AnnotatedMethodClass.getMethodMultipleAnnotation(), 133 "@Container({@Repeated(1), @Repeated(2)})"); 134 assertOnlyParameterAnnotations( 135 AnnotatedMethodClass.getMethodSingleAnnotation(), 136 "@Repeated(1)"); 137 assertOnlyParameterAnnotations( 138 AnnotatedMethodClass.getMethodStaticSingleAnnotation(), 139 "@Repeated(1)"); 140 assertOnlyParameterAnnotations( 141 AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(), 142 "@Repeated(1)"); 143 144 } 145 146 private static class ConstructorClass { 147 // No annotations. 148 public ConstructorClass(Integer parameter1, Integer parameter2) {} 149 150 // Annotations. 151 public ConstructorClass(@AnnotationB @AnnotationD String parameter1, 152 @AnnotationC @AnnotationD String parameter2) {} 153 } 154 155 public void testConstructorGetParameterAnnotations() throws Exception { 156 Constructor constructorWithoutAnnotatedParameters = 157 ConstructorClass.class.getDeclaredConstructor(Integer.class, Integer.class); 158 Annotation[][] noParameterAnnotations = getParameterAnnotations( 159 constructorWithoutAnnotatedParameters, 2); 160 assertEquals(set(), annotationsToTypes(noParameterAnnotations[0])); 161 assertEquals(set(), annotationsToTypes(noParameterAnnotations[1])); 162 163 Constructor constructorWithAnnotatedParameters = 164 ConstructorClass.class.getDeclaredConstructor(String.class, String.class); 165 Annotation[][] parameterAnnotations = getParameterAnnotations( 166 constructorWithAnnotatedParameters, 2); 167 assertEquals(set(AnnotationB.class, AnnotationD.class), 168 annotationsToTypes(parameterAnnotations[0])); 169 assertEquals(set(AnnotationC.class, AnnotationD.class), 170 annotationsToTypes(parameterAnnotations[1])); 171 } 172 173 private static class AnnotatedConstructorClass { 174 public AnnotatedConstructorClass(Boolean p0) {} 175 176 public AnnotatedConstructorClass( 177 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {} 178 179 public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {} 180 181 public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {} 182 183 public AnnotatedConstructorClass(@Repeated(1) String p0) {} 184 185 static Constructor<?> getConstructorWithoutAnnotations() throws Exception { 186 return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class); 187 } 188 189 static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception { 190 return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class); 191 } 192 193 static Constructor<?> getConstructorMultipleAnnotationExplicitSingle() 194 throws Exception { 195 return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class); 196 } 197 198 static Constructor<?> getConstructorMultipleAnnotation() throws Exception { 199 return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class); 200 } 201 202 static Constructor<?> getConstructorSingleAnnotation() throws Exception { 203 return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class); 204 } 205 } 206 207 public void testConstructorGetParameterAnnotations_repeated() throws Exception { 208 assertOnlyParameterAnnotations( 209 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 210 EXPECT_EMPTY); 211 assertOnlyParameterAnnotations( 212 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 213 "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})"); 214 assertOnlyParameterAnnotations( 215 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 216 "@Container({@Repeated(1)})"); 217 assertOnlyParameterAnnotations( 218 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 219 "@Container({@Repeated(1), @Repeated(2)})"); 220 assertOnlyParameterAnnotations( 221 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 222 "@Repeated(1)"); 223 } 224 225 /** 226 * As an inner class the constructor will actually have two parameters: the first, referencing 227 * the enclosing object, is inserted by the compiler. 228 */ 229 class InnerClass { 230 InnerClass(@AnnotationA String p1) {} 231 } 232 233 /** Special case testing for a compiler-generated constructor parameter. JLS 8.8.1, JLS 13.1. */ 234 public void testImplicitConstructorParameters_innerClass() throws Exception { 235 Constructor<InnerClass> constructor = 236 InnerClass.class.getDeclaredConstructor( 237 ExecutableParameterTest.class, String.class); 238 239 // The parameter annotation code behaves as if there are two parameters. 240 Annotation[][] annotations = getParameterAnnotations(constructor, 2); 241 assertAnnotationsMatch(annotations[0], new String[0]); 242 assertAnnotationsMatch(annotations[1], new String[] { "@AnnotationA" }); 243 } 244 245 static abstract class AnonymousBaseClass { 246 public AnonymousBaseClass(@AnnotationA String p1) {} 247 } 248 249 /** Special case testing for a compiler-generated constructor parameter. JLS 13.1 */ 250 public void testImplicitConstructorParameters_anonymousClass() throws Exception { 251 /* 252 * As an anonymous class the constructor will actually have two parameters: the first, 253 * referencing the enclosing object, is inserted by the compiler. 254 */ 255 AnonymousBaseClass anonymousClassInstance = new AnonymousBaseClass("p1") {}; 256 257 Constructor<? extends AnonymousBaseClass> constructor = 258 anonymousClassInstance.getClass().getDeclaredConstructor( 259 ExecutableParameterTest.class, String.class); 260 // The parameter annotation code behaves as if there are two parameters. 261 Annotation[][] annotations = getParameterAnnotations(constructor, 2); 262 assertAnnotationsMatch(annotations[0], new String[0]); 263 assertAnnotationsMatch(annotations[1], new String[0]); 264 } 265 266 /** 267 * A static inner / nested member class will not have synthetic parameters and should behave 268 * like a top-level class. 269 */ 270 static class StaticInnerClass { 271 StaticInnerClass(@AnnotationA String p1) {} 272 } 273 274 /** Special case testing for a compiler-generated constructor parameter. */ 275 public void testImplicitConstructorParameters_staticInnerClass() throws Exception { 276 Constructor<StaticInnerClass> constructor = 277 StaticInnerClass.class.getDeclaredConstructor(String.class); 278 Parameter[] parameters = constructor.getParameters(); 279 assertEquals(1, parameters.length); 280 281 Annotation[][] annotations = getParameterAnnotations(constructor, 1); 282 assertAnnotationsMatch(annotations[0], new String[] { "@AnnotationA" }); 283 } 284 285 private static void assertOnlyParameterAnnotations( 286 Executable executable, String... expectedAnnotationStrings) throws Exception { 287 Annotation[][] allAnnotations = getParameterAnnotations(executable, 1); 288 289 Annotation[] p0Annotations = allAnnotations[0]; 290 assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings); 291 } 292 293 private static Annotation[][] getParameterAnnotations( 294 Executable executable, int expectedParameterAnnotationsSize) { 295 Annotation[][] allAnnotations = executable.getParameterAnnotations(); 296 assertEquals(expectedParameterAnnotationsSize, allAnnotations.length); 297 return allAnnotations; 298 } 299 } 300