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 17package libcore.java.lang.reflect.annotations; 18 19import junit.framework.TestCase; 20 21import java.lang.annotation.Annotation; 22import java.lang.reflect.Constructor; 23import java.lang.reflect.Executable; 24import java.lang.reflect.Method; 25import java.lang.reflect.Parameter; 26import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; 27import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; 28import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; 29import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; 30import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; 31 32import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; 33import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; 34import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; 35import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; 36 37/** 38 * Tests for the {@link java.lang.reflect.AnnotatedElement} methods from the {@link Parameter} 39 * objects obtained from both {@link Constructor} and {@link Method}. 40 */ 41public class AnnotatedElementParameterTest extends TestCase { 42 43 private static class MethodClass { 44 public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {} 45 46 public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1, 47 @AnnotationC @AnnotationD String parameter2) {} 48 } 49 50 public void testMethodParameterAnnotations() throws Exception { 51 Class<?> c = MethodClass.class; 52 { 53 Parameter[] parameters = c.getDeclaredMethod( 54 "methodWithoutAnnotatedParameters", String.class, String.class).getParameters(); 55 Parameter parameter0 = parameters[0]; 56 checkAnnotatedElementPresentMethods(parameter0); 57 58 Parameter parameter1 = parameters[1]; 59 checkAnnotatedElementPresentMethods(parameter1); 60 } 61 { 62 Parameter[] parameters = c.getDeclaredMethod( 63 "methodWithAnnotatedParameters", String.class, String.class).getParameters(); 64 65 Parameter parameter0 = parameters[0]; 66 checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class); 67 68 Parameter parameter1 = parameters[1]; 69 checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class); 70 } 71 } 72 73 private static class ConstructorClass { 74 // No annotations. 75 public ConstructorClass(Integer parameter1, Integer parameter2) {} 76 77 // Annotations. 78 public ConstructorClass(@AnnotationB @AnnotationD String parameter1, 79 @AnnotationC @AnnotationD String parameter2) {} 80 } 81 82 public void testConstructorParameterAnnotations() throws Exception { 83 Class<?> c = ConstructorClass.class; 84 { 85 Parameter[] parameters = 86 c.getDeclaredConstructor(Integer.class, Integer.class).getParameters(); 87 Parameter parameter0 = parameters[0]; 88 checkAnnotatedElementPresentMethods(parameter0); 89 90 Parameter parameter1 = parameters[1]; 91 checkAnnotatedElementPresentMethods(parameter1); 92 } 93 { 94 Parameter[] parameters = 95 c.getDeclaredConstructor(String.class, String.class).getParameters(); 96 97 Parameter parameter0 = parameters[0]; 98 checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class); 99 100 Parameter parameter1 = parameters[1]; 101 checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class); 102 } 103 } 104 105 private static class AnnotatedMethodClass { 106 void noAnnotation(String p0) {} 107 108 void multipleAnnotationOddity( 109 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {} 110 111 void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {} 112 113 void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {} 114 115 void singleAnnotation(@Repeated(1) String p0) {} 116 117 static void staticSingleAnnotation(@Repeated(1) String p0) {} 118 119 static Method getMethodWithoutAnnotations() throws Exception { 120 return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class); 121 } 122 123 static Method getMethodMultipleAnnotationOddity() throws Exception { 124 return AnnotatedMethodClass.class.getDeclaredMethod( 125 "multipleAnnotationOddity", String.class); 126 } 127 128 static Method getMethodMultipleAnnotationExplicitSingle() throws Exception { 129 return AnnotatedMethodClass.class.getDeclaredMethod( 130 "multipleAnnotationExplicitSingle", String.class); 131 } 132 133 static Method getMethodMultipleAnnotation() throws Exception { 134 return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class); 135 } 136 137 static Method getMethodSingleAnnotation() throws Exception { 138 return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class); 139 } 140 141 static Method getMethodStaticSingleAnnotation() throws Exception { 142 return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation", 143 String.class); 144 } 145 } 146 147 private static abstract class AnnotatedMethodAbstractClass { 148 abstract void abstractSingleAnnotation(@Repeated(1) String p0); 149 150 static Method getMethodAbstractSingleAnnotation() throws Exception { 151 return AnnotatedMethodAbstractClass.class.getDeclaredMethod( 152 "abstractSingleAnnotation", String.class); 153 } 154 } 155 156 // Tests for isAnnotationPresent and getDeclaredAnnotation. 157 public void testMethodDeclaredAnnotation() throws Exception { 158 Class<? extends Annotation> repeated = Repeated.class; 159 checkParameter0DeclaredAnnotation( 160 AnnotatedMethodClass.getMethodWithoutAnnotations(), 161 repeated, null); 162 checkParameter0DeclaredAnnotation( 163 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 164 repeated, "@Repeated(1)"); 165 checkParameter0DeclaredAnnotation( 166 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 167 repeated, null); 168 checkParameter0DeclaredAnnotation( 169 AnnotatedMethodClass.getMethodMultipleAnnotation(), 170 repeated, null); 171 checkParameter0DeclaredAnnotation( 172 AnnotatedMethodClass.getMethodSingleAnnotation(), 173 repeated, "@Repeated(1)"); 174 checkParameter0DeclaredAnnotation( 175 AnnotatedMethodClass.getMethodStaticSingleAnnotation(), 176 repeated, "@Repeated(1)"); 177 checkParameter0DeclaredAnnotation( 178 AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(), 179 repeated, "@Repeated(1)"); 180 181 Class<? extends Annotation> container = Container.class; 182 checkParameter0DeclaredAnnotation( 183 AnnotatedMethodClass.getMethodWithoutAnnotations(), 184 container, null); 185 checkParameter0DeclaredAnnotation( 186 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 187 container, "@Container({@Repeated(2), @Repeated(3)})"); 188 checkParameter0DeclaredAnnotation( 189 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 190 container, "@Container({@Repeated(1)})"); 191 checkParameter0DeclaredAnnotation( 192 AnnotatedMethodClass.getMethodMultipleAnnotation(), 193 container, "@Container({@Repeated(1), @Repeated(2)})"); 194 checkParameter0DeclaredAnnotation( 195 AnnotatedMethodClass.getMethodSingleAnnotation(), 196 container, null); 197 } 198 199 private static class AnnotatedConstructorClass { 200 public AnnotatedConstructorClass(Boolean p0) {} 201 202 public AnnotatedConstructorClass( 203 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {} 204 205 public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {} 206 207 public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {} 208 209 public AnnotatedConstructorClass(@Repeated(1) String p0) {} 210 211 static Constructor<?> getConstructorWithoutAnnotations() throws Exception { 212 return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class); 213 } 214 215 static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception { 216 return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class); 217 } 218 219 static Constructor<?> getConstructorMultipleAnnotationExplicitSingle() 220 throws Exception { 221 return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class); 222 } 223 224 static Constructor<?> getConstructorSingleAnnotation() throws Exception { 225 return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class); 226 } 227 228 static Constructor<?> getConstructorMultipleAnnotation() throws Exception { 229 return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class); 230 } 231 } 232 233 // Tests for isAnnotationPresent and getDeclaredAnnotation. 234 public void testConstructorDeclaredAnnotation() throws Exception { 235 Class<? extends Annotation> repeated = Repeated.class; 236 checkParameter0DeclaredAnnotation( 237 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 238 repeated, null); 239 checkParameter0DeclaredAnnotation( 240 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 241 repeated, "@Repeated(1)"); 242 checkParameter0DeclaredAnnotation( 243 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 244 repeated, null); 245 checkParameter0DeclaredAnnotation( 246 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 247 repeated, null); 248 checkParameter0DeclaredAnnotation( 249 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 250 repeated, "@Repeated(1)"); 251 252 Class<? extends Annotation> container = Container.class; 253 checkParameter0DeclaredAnnotation( 254 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 255 container, null); 256 checkParameter0DeclaredAnnotation( 257 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 258 container, "@Container({@Repeated(2), @Repeated(3)})"); 259 checkParameter0DeclaredAnnotation( 260 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 261 container, "@Container({@Repeated(1)})"); 262 checkParameter0DeclaredAnnotation( 263 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 264 container, "@Container({@Repeated(1), @Repeated(2)})"); 265 checkParameter0DeclaredAnnotation( 266 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 267 container, null); 268 } 269 270 private static void checkParameter0DeclaredAnnotation( 271 Executable executable, Class<? extends Annotation> annotationType, 272 String expectedAnnotationString) throws Exception { 273 Parameter parameter = executable.getParameters()[0]; 274 275 // isAnnotationPresent 276 assertIsAnnotationPresent(parameter, annotationType, expectedAnnotationString != null); 277 278 // getDeclaredAnnotation 279 assertGetDeclaredAnnotation(parameter, annotationType, expectedAnnotationString); 280 } 281 282 public void testMethodGetDeclaredAnnotationsByType() throws Exception { 283 Class<? extends Annotation> repeated = Repeated.class; 284 checkParameter0GetDeclaredAnnotationsByType( 285 AnnotatedMethodClass.getMethodWithoutAnnotations(), 286 repeated, EXPECT_EMPTY); 287 checkParameter0GetDeclaredAnnotationsByType( 288 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 289 repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); 290 checkParameter0GetDeclaredAnnotationsByType( 291 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 292 repeated, "@Repeated(1)"); 293 checkParameter0GetDeclaredAnnotationsByType( 294 AnnotatedMethodClass.getMethodMultipleAnnotation(), 295 repeated, "@Repeated(1)", "@Repeated(2)"); 296 checkParameter0GetDeclaredAnnotationsByType( 297 AnnotatedMethodClass.getMethodSingleAnnotation(), 298 repeated, "@Repeated(1)"); 299 300 Class<? extends Annotation> container = Container.class; 301 checkParameter0GetDeclaredAnnotationsByType( 302 AnnotatedMethodClass.getMethodWithoutAnnotations(), 303 container, EXPECT_EMPTY); 304 checkParameter0GetDeclaredAnnotationsByType( 305 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 306 container, "@Container({@Repeated(2), @Repeated(3)})"); 307 checkParameter0GetDeclaredAnnotationsByType( 308 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 309 container, "@Container({@Repeated(1)})"); 310 checkParameter0GetDeclaredAnnotationsByType( 311 AnnotatedMethodClass.getMethodMultipleAnnotation(), 312 container, "@Container({@Repeated(1), @Repeated(2)})"); 313 checkParameter0GetDeclaredAnnotationsByType( 314 AnnotatedMethodClass.getMethodSingleAnnotation(), 315 container, EXPECT_EMPTY); 316 } 317 318 public void testConstructorGetDeclaredAnnotationsByType() throws Exception { 319 Class<? extends Annotation> repeated = Repeated.class; 320 checkParameter0GetDeclaredAnnotationsByType( 321 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 322 repeated, EXPECT_EMPTY); 323 checkParameter0GetDeclaredAnnotationsByType( 324 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 325 repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); 326 checkParameter0GetDeclaredAnnotationsByType( 327 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 328 repeated, "@Repeated(1)"); 329 checkParameter0GetDeclaredAnnotationsByType( 330 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 331 repeated, "@Repeated(1)", "@Repeated(2)"); 332 checkParameter0GetDeclaredAnnotationsByType( 333 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 334 repeated, "@Repeated(1)"); 335 336 Class<? extends Annotation> container = Container.class; 337 checkParameter0GetDeclaredAnnotationsByType( 338 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 339 container, EXPECT_EMPTY); 340 checkParameter0GetDeclaredAnnotationsByType( 341 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 342 container, "@Container({@Repeated(2), @Repeated(3)})"); 343 checkParameter0GetDeclaredAnnotationsByType( 344 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 345 container, "@Container({@Repeated(1)})"); 346 checkParameter0GetDeclaredAnnotationsByType( 347 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 348 container, "@Container({@Repeated(1), @Repeated(2)})"); 349 checkParameter0GetDeclaredAnnotationsByType( 350 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 351 container, EXPECT_EMPTY); 352 } 353 354 private static void checkParameter0GetDeclaredAnnotationsByType( 355 Executable executable, Class<? extends Annotation> annotationType, 356 String... expectedAnnotationStrings) throws Exception { 357 Parameter parameter = executable.getParameters()[0]; 358 AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( 359 parameter, annotationType, expectedAnnotationStrings); 360 } 361 362 public void testMethodGetAnnotationsByType() throws Exception { 363 Class<? extends Annotation> repeated = Repeated.class; 364 checkParameter0GetAnnotationsByType( 365 AnnotatedMethodClass.getMethodWithoutAnnotations(), 366 repeated, EXPECT_EMPTY); 367 checkParameter0GetAnnotationsByType( 368 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 369 repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); 370 checkParameter0GetAnnotationsByType( 371 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 372 repeated, "@Repeated(1)"); 373 checkParameter0GetAnnotationsByType( 374 AnnotatedMethodClass.getMethodMultipleAnnotation(), 375 repeated, "@Repeated(1)", "@Repeated(2)"); 376 checkParameter0GetAnnotationsByType( 377 AnnotatedMethodClass.getMethodSingleAnnotation(), 378 repeated, "@Repeated(1)"); 379 380 Class<? extends Annotation> container = Container.class; 381 checkParameter0GetAnnotationsByType( 382 AnnotatedMethodClass.getMethodWithoutAnnotations(), 383 container, EXPECT_EMPTY); 384 checkParameter0GetAnnotationsByType( 385 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(), 386 container, "@Container({@Repeated(2), @Repeated(3)})"); 387 checkParameter0GetAnnotationsByType( 388 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(), 389 container, "@Container({@Repeated(1)})"); 390 checkParameter0GetAnnotationsByType( 391 AnnotatedMethodClass.getMethodMultipleAnnotation(), 392 container, "@Container({@Repeated(1), @Repeated(2)})"); 393 checkParameter0GetAnnotationsByType( 394 AnnotatedMethodClass.getMethodSingleAnnotation(), 395 container, EXPECT_EMPTY); 396 } 397 398 public void testConstructorGetAnnotationsByType() throws Exception { 399 Class<? extends Annotation> repeated = Repeated.class; 400 checkParameter0GetAnnotationsByType( 401 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 402 repeated, EXPECT_EMPTY); 403 checkParameter0GetAnnotationsByType( 404 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 405 repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); 406 checkParameter0GetAnnotationsByType( 407 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 408 repeated, "@Repeated(1)"); 409 checkParameter0GetAnnotationsByType( 410 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 411 repeated, "@Repeated(1)", "@Repeated(2)"); 412 checkParameter0GetAnnotationsByType( 413 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 414 repeated, "@Repeated(1)"); 415 416 Class<? extends Annotation> container = Container.class; 417 checkParameter0GetAnnotationsByType( 418 AnnotatedConstructorClass.getConstructorWithoutAnnotations(), 419 container, EXPECT_EMPTY); 420 checkParameter0GetAnnotationsByType( 421 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(), 422 container, "@Container({@Repeated(2), @Repeated(3)})"); 423 checkParameter0GetAnnotationsByType( 424 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(), 425 container, "@Container({@Repeated(1)})"); 426 checkParameter0GetAnnotationsByType( 427 AnnotatedConstructorClass.getConstructorMultipleAnnotation(), 428 container, "@Container({@Repeated(1), @Repeated(2)})"); 429 checkParameter0GetAnnotationsByType( 430 AnnotatedConstructorClass.getConstructorSingleAnnotation(), 431 container, EXPECT_EMPTY); 432 } 433 434 private static void checkParameter0GetAnnotationsByType( 435 Executable executable, Class<? extends Annotation> annotationType, 436 String... expectedAnnotationStrings) throws Exception { 437 Parameter parameter = executable.getParameters()[0]; 438 AnnotatedElementTestSupport.assertGetAnnotationsByType( 439 parameter, annotationType, expectedAnnotationStrings); 440 } 441 442 /** 443 * As an inner class the constructor will actually have two parameters: the first, referencing 444 * the enclosing object, is inserted by the compiler. 445 */ 446 class InnerClass { 447 InnerClass(@Repeated(1) String p1) {} 448 } 449 450 /** Special case testing for a compiler-generated constructor parameter. */ 451 public void testImplicitConstructorParameters_singleAnnotation() throws Exception { 452 Constructor<InnerClass> constructor = 453 InnerClass.class.getDeclaredConstructor( 454 AnnotatedElementParameterTest.class, String.class); 455 Parameter[] parameters = constructor.getParameters(); 456 457 // The compiler-generated constructor should have no annotations. 458 Parameter parameter0 = parameters[0]; 459 AnnotatedElementTestSupport.assertGetAnnotationsByType( 460 parameter0, Repeated.class, new String[0]); 461 AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( 462 parameter0, Repeated.class, new String[0]); 463 AnnotatedElementTestSupport.assertGetDeclaredAnnotation( 464 parameter0, Repeated.class, null); 465 AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, Repeated.class, false); 466 467 // The annotation should remain on the correct parameter. 468 Parameter parameter1 = parameters[1]; 469 AnnotatedElementTestSupport.assertGetAnnotationsByType( 470 parameter1, Repeated.class, new String[] {"@Repeated(1)"}); 471 AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( 472 parameter1, Repeated.class, new String[] {"@Repeated(1)"}); 473 AnnotatedElementTestSupport.assertGetDeclaredAnnotation( 474 parameter1, Repeated.class, "@Repeated(1)"); 475 AnnotatedElementTestSupport.assertIsAnnotationPresent( 476 parameter1, Repeated.class, true); 477 } 478} 479