1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8004698 27 * @summary Unit test for type annotations 28 */ 29 30 import java.util.*; 31 import java.lang.annotation.*; 32 import java.lang.reflect.*; 33 import java.io.Serializable; 34 35 public class TypeAnnotationReflection { 36 public static void main(String[] args) throws Exception { 37 testSuper(); 38 testInterfaces(); 39 testReturnType(); 40 testNested(); 41 testArray(); 42 testRunException(); 43 testClassTypeVarBounds(); 44 testMethodTypeVarBounds(); 45 testFields(); 46 testClassTypeVar(); 47 testMethodTypeVar(); 48 testParameterizedType(); 49 testNestedParameterizedType(); 50 testWildcardType(); 51 } 52 53 private static void check(boolean b) { 54 if (!b) 55 throw new RuntimeException(); 56 } 57 58 private static void testSuper() throws Exception { 59 check(Object.class.getAnnotatedSuperclass().getAnnotations().length == 0); 60 check(Class.class.getAnnotatedSuperclass().getAnnotations().length == 0); 61 62 AnnotatedType a; 63 a = TestClassArray.class.getAnnotatedSuperclass(); 64 Annotation[] annos = a.getAnnotations(); 65 check(annos.length == 2); 66 check(annos[0].annotationType().equals(TypeAnno.class)); 67 check(annos[1].annotationType().equals(TypeAnno2.class)); 68 check(((TypeAnno)annos[0]).value().equals("extends")); 69 check(((TypeAnno2)annos[1]).value().equals("extends2")); 70 } 71 72 private static void testInterfaces() throws Exception { 73 AnnotatedType[] as; 74 as = TestClassArray.class.getAnnotatedInterfaces(); 75 check(as.length == 3); 76 check(as[1].getAnnotations().length == 0); 77 78 Annotation[] annos; 79 annos = as[0].getAnnotations(); 80 check(annos.length == 2); 81 check(annos[0].annotationType().equals(TypeAnno.class)); 82 check(annos[1].annotationType().equals(TypeAnno2.class)); 83 check(((TypeAnno)annos[0]).value().equals("implements serializable")); 84 check(((TypeAnno2)annos[1]).value().equals("implements2 serializable")); 85 86 annos = as[2].getAnnotations(); 87 check(annos.length == 2); 88 check(annos[0].annotationType().equals(TypeAnno.class)); 89 check(annos[1].annotationType().equals(TypeAnno2.class)); 90 check(((TypeAnno)annos[0]).value().equals("implements cloneable")); 91 check(((TypeAnno2)annos[1]).value().equals("implements2 cloneable")); 92 } 93 94 private static void testReturnType() throws Exception { 95 Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null); 96 Annotation[] annos = m.getAnnotatedReturnType().getAnnotations(); 97 check(annos.length == 1); 98 check(annos[0].annotationType().equals(TypeAnno.class)); 99 check(((TypeAnno)annos[0]).value().equals("return1")); 100 } 101 102 private static void testNested() throws Exception { 103 Method m = TestClassNested.class.getDeclaredMethod("foo", (Class<?>[])null); 104 Annotation[] annos = m.getAnnotatedReturnType().getAnnotations(); 105 check(annos.length == 1); 106 check(annos[0].annotationType().equals(TypeAnno.class)); 107 check(((TypeAnno)annos[0]).value().equals("array")); 108 109 AnnotatedType t = m.getAnnotatedReturnType(); 110 t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType(); 111 annos = t.getAnnotations(); 112 check(annos.length == 1); 113 check(annos[0].annotationType().equals(TypeAnno.class)); 114 check(((TypeAnno)annos[0]).value().equals("Inner")); 115 } 116 117 private static void testArray() throws Exception { 118 Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null); 119 AnnotatedArrayType t = (AnnotatedArrayType) m.getAnnotatedReturnType(); 120 Annotation[] annos = t.getAnnotations(); 121 check(annos.length == 1); 122 check(annos[0].annotationType().equals(TypeAnno.class)); 123 check(((TypeAnno)annos[0]).value().equals("return1")); 124 125 t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType(); 126 annos = t.getAnnotations(); 127 check(annos.length == 0); 128 129 t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType(); 130 annos = t.getAnnotations(); 131 check(annos.length == 1); 132 check(annos[0].annotationType().equals(TypeAnno.class)); 133 check(((TypeAnno)annos[0]).value().equals("return3")); 134 135 AnnotatedType tt = t.getAnnotatedGenericComponentType(); 136 check(!(tt instanceof AnnotatedArrayType)); 137 annos = tt.getAnnotations(); 138 check(annos.length == 1); 139 check(annos[0].annotationType().equals(TypeAnno.class)); 140 check(((TypeAnno)annos[0]).value().equals("return4")); 141 } 142 143 private static void testRunException() throws Exception { 144 Method m = TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null); 145 AnnotatedType[] ts = m.getAnnotatedExceptionTypes(); 146 check(ts.length == 3); 147 148 AnnotatedType t; 149 Annotation[] annos; 150 t = ts[0]; 151 annos = t.getAnnotations(); 152 check(annos.length == 2); 153 check(annos[0].annotationType().equals(TypeAnno.class)); 154 check(annos[1].annotationType().equals(TypeAnno2.class)); 155 check(((TypeAnno)annos[0]).value().equals("RE")); 156 check(((TypeAnno2)annos[1]).value().equals("RE2")); 157 158 t = ts[1]; 159 annos = t.getAnnotations(); 160 check(annos.length == 0); 161 162 t = ts[2]; 163 annos = t.getAnnotations(); 164 check(annos.length == 1); 165 check(annos[0].annotationType().equals(TypeAnno.class)); 166 check(((TypeAnno)annos[0]).value().equals("AIOOBE")); 167 } 168 169 private static void testClassTypeVarBounds() throws Exception { 170 Method m = TestClassTypeVarAndField.class.getDeclaredMethod("foo", (Class<?>[])null); 171 AnnotatedType ret = m.getAnnotatedReturnType(); 172 Annotation[] annos = ret.getAnnotations(); 173 check(annos.length == 2); 174 175 AnnotatedType[] annotatedBounds = ((AnnotatedTypeVariable)ret).getAnnotatedBounds(); 176 check(annotatedBounds.length == 2); 177 178 annos = annotatedBounds[0].getAnnotations(); 179 check(annos.length == 1); 180 check(annos[0].annotationType().equals(TypeAnno.class)); 181 check(((TypeAnno)annos[0]).value().equals("Object1")); 182 183 annos = annotatedBounds[1].getAnnotations(); 184 check(annos.length == 2); 185 check(annos[0].annotationType().equals(TypeAnno.class)); 186 check(annos[1].annotationType().equals(TypeAnno2.class)); 187 check(((TypeAnno)annos[0]).value().equals("Runnable1")); 188 check(((TypeAnno2)annos[1]).value().equals("Runnable2")); 189 } 190 191 private static void testMethodTypeVarBounds() throws Exception { 192 Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null); 193 AnnotatedType ret2 = m2.getAnnotatedReturnType(); 194 AnnotatedType[] annotatedBounds2 = ((AnnotatedTypeVariable)ret2).getAnnotatedBounds(); 195 check(annotatedBounds2.length == 1); 196 197 Annotation[] annos = annotatedBounds2[0].getAnnotations(); 198 check(annos.length == 1); 199 check(annos[0].annotationType().equals(TypeAnno.class)); 200 check(((TypeAnno)annos[0]).value().equals("M Runnable")); 201 } 202 203 private static void testFields() throws Exception { 204 Field f1 = TestClassTypeVarAndField.class.getDeclaredField("field1"); 205 AnnotatedType at; 206 Annotation[] annos; 207 208 at = f1.getAnnotatedType(); 209 annos = at.getAnnotations(); 210 check(annos.length == 2); 211 check(annos[0].annotationType().equals(TypeAnno.class)); 212 check(annos[1].annotationType().equals(TypeAnno2.class)); 213 check(((TypeAnno)annos[0]).value().equals("T1 field")); 214 check(((TypeAnno2)annos[1]).value().equals("T2 field")); 215 216 Field f2 = TestClassTypeVarAndField.class.getDeclaredField("field2"); 217 at = f2.getAnnotatedType(); 218 annos = at.getAnnotations(); 219 check(annos.length == 0); 220 221 Field f3 = TestClassTypeVarAndField.class.getDeclaredField("field3"); 222 at = f3.getAnnotatedType(); 223 annos = at.getAnnotations(); 224 check(annos.length == 1); 225 check(annos[0].annotationType().equals(TypeAnno.class)); 226 check(((TypeAnno)annos[0]).value().equals("Object field")); 227 } 228 229 private static void testClassTypeVar() throws Exception { 230 TypeVariable[] typeVars = TestClassTypeVarAndField.class.getTypeParameters(); 231 Annotation[] annos; 232 check(typeVars.length == 2); 233 234 // First TypeVar 235 AnnotatedType[] annotatedBounds = typeVars[0].getAnnotatedBounds(); 236 check(annotatedBounds.length == 2); 237 238 annos = annotatedBounds[0].getAnnotations(); 239 check(annos.length == 1); 240 check(annos[0].annotationType().equals(TypeAnno.class)); 241 check(((TypeAnno)annos[0]).value().equals("Object1")); 242 243 annos = annotatedBounds[1].getAnnotations(); 244 check(annos.length == 2); 245 check(annos[0].annotationType().equals(TypeAnno.class)); 246 check(annos[1].annotationType().equals(TypeAnno2.class)); 247 check(((TypeAnno)annos[0]).value().equals("Runnable1")); 248 check(((TypeAnno2)annos[1]).value().equals("Runnable2")); 249 250 // second TypeVar regular anno 251 Annotation[] regularAnnos = typeVars[1].getAnnotations(); 252 check(regularAnnos.length == 1); 253 check(typeVars[1].getAnnotation(TypeAnno.class).value().equals("EE")); 254 255 // second TypeVar 256 annotatedBounds = typeVars[1].getAnnotatedBounds(); 257 check(annotatedBounds.length == 1); 258 259 annos = annotatedBounds[0].getAnnotations(); 260 check(annos.length == 1); 261 check(annos[0].annotationType().equals(TypeAnno2.class)); 262 check(((TypeAnno2)annos[0]).value().equals("EEBound")); 263 } 264 265 private static void testMethodTypeVar() throws Exception { 266 Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null); 267 TypeVariable[] t = m2.getTypeParameters(); 268 check(t.length == 1); 269 Annotation[] annos = t[0].getAnnotations(); 270 check(annos.length == 0); 271 272 AnnotatedType[] annotatedBounds2 = t[0].getAnnotatedBounds(); 273 check(annotatedBounds2.length == 1); 274 275 annos = annotatedBounds2[0].getAnnotations(); 276 check(annos.length == 1); 277 check(annos[0].annotationType().equals(TypeAnno.class)); 278 check(((TypeAnno)annos[0]).value().equals("M Runnable")); 279 280 // Second method 281 m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo3", (Class<?>[])null); 282 t = m2.getTypeParameters(); 283 check(t.length == 1); 284 annos = t[0].getAnnotations(); 285 check(annos.length == 1); 286 check(annos[0].annotationType().equals(TypeAnno.class)); 287 check(((TypeAnno)annos[0]).value().equals("K")); 288 289 annotatedBounds2 = t[0].getAnnotatedBounds(); 290 check(annotatedBounds2.length == 1); 291 292 annos = annotatedBounds2[0].getAnnotations(); 293 check(annos.length == 0); 294 } 295 296 private static void testParameterizedType() { 297 // Base 298 AnnotatedType[] as; 299 as = TestParameterizedType.class.getAnnotatedInterfaces(); 300 check(as.length == 1); 301 check(as[0].getAnnotations().length == 1); 302 check(as[0].getAnnotation(TypeAnno.class).value().equals("M")); 303 304 Annotation[] annos; 305 as = ((AnnotatedParameterizedType)as[0]).getAnnotatedActualTypeArguments(); 306 check(as.length == 2); 307 annos = as[0].getAnnotations(); 308 check(annos.length == 1); 309 check(as[0].getAnnotation(TypeAnno.class).value().equals("S")); 310 check(as[0].getAnnotation(TypeAnno2.class) == null); 311 312 annos = as[1].getAnnotations(); 313 check(annos.length == 2); 314 check(((TypeAnno)annos[0]).value().equals("I")); 315 check(as[1].getAnnotation(TypeAnno2.class).value().equals("I2")); 316 } 317 318 private static void testNestedParameterizedType() throws Exception { 319 Method m = TestParameterizedType.class.getDeclaredMethod("foo2", (Class<?>[])null); 320 AnnotatedType ret = m.getAnnotatedReturnType(); 321 Annotation[] annos; 322 annos = ret.getAnnotations(); 323 check(annos.length == 1); 324 check(((TypeAnno)annos[0]).value().equals("I")); 325 326 AnnotatedType[] args = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments(); 327 check(args.length == 1); 328 annos = args[0].getAnnotations(); 329 check(annos.length == 2); 330 check(((TypeAnno)annos[0]).value().equals("I1")); 331 check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2")); 332 } 333 334 private static void testWildcardType() throws Exception { 335 Method m = TestWildcardType.class.getDeclaredMethod("foo", (Class<?>[])null); 336 AnnotatedType ret = m.getAnnotatedReturnType(); 337 AnnotatedType[] t; 338 t = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments(); 339 check(t.length == 1); 340 ret = t[0]; 341 342 Field f = TestWildcardType.class.getDeclaredField("f1"); 343 AnnotatedWildcardType w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f 344 .getAnnotatedType()).getAnnotatedActualTypeArguments()[0]; 345 t = w.getAnnotatedLowerBounds(); 346 check(t.length == 0); 347 t = w.getAnnotatedUpperBounds(); 348 check(t.length == 1); 349 Annotation[] annos; 350 annos = t[0].getAnnotations(); 351 check(annos.length == 1); 352 check(((TypeAnno)annos[0]).value().equals("2")); 353 354 f = TestWildcardType.class.getDeclaredField("f2"); 355 w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f 356 .getAnnotatedType()).getAnnotatedActualTypeArguments()[0]; 357 t = w.getAnnotatedUpperBounds(); 358 check(t.length == 0); 359 t = w.getAnnotatedLowerBounds(); 360 check(t.length == 1); 361 } 362 } 363 364 abstract class TestWildcardType { 365 public <T> List<? super T> foo() { return null;} 366 public Class<@TypeAnno("1") ? extends @TypeAnno("2") Annotation> f1; 367 public Class<@TypeAnno("3") ? super @TypeAnno("4") Annotation> f2; 368 } 369 370 abstract class TestParameterizedType implements @TypeAnno("M") Map<@TypeAnno("S")String, @TypeAnno("I") @TypeAnno2("I2")Integer> { 371 public ParameterizedOuter<String>.ParameterizedInner<Integer> foo() {return null;} 372 public @TypeAnno("O") ParameterizedOuter<@TypeAnno("S1") @TypeAnno2("S2") String>. 373 @TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() { 374 return null; 375 } 376 } 377 378 class ParameterizedOuter <T> { 379 class ParameterizedInner <U> {} 380 } 381 382 abstract class TestClassArray extends @TypeAnno("extends") @TypeAnno2("extends2") Object 383 implements @TypeAnno("implements serializable") @TypeAnno2("implements2 serializable") Serializable, 384 Readable, 385 @TypeAnno("implements cloneable") @TypeAnno2("implements2 cloneable") Cloneable { 386 public @TypeAnno("return4") Object @TypeAnno("return1") [][] @TypeAnno("return3")[] foo() { return null; } 387 } 388 389 abstract class TestClassNested { 390 public @TypeAnno("Outer") Outer.@TypeAnno("Inner")Inner @TypeAnno("array")[] foo() { return null; } 391 } 392 393 class Outer { 394 class Inner { 395 } 396 } 397 398 abstract class TestClassException { 399 public Object foo() throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException, 400 NullPointerException, 401 @TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException { 402 return null; 403 } 404 } 405 406 abstract class TestClassTypeVarAndField <T extends @TypeAnno("Object1") Object 407 & @TypeAnno("Runnable1") @TypeAnno2("Runnable2") Runnable, 408 @TypeAnno("EE")EE extends @TypeAnno2("EEBound") Runnable > { 409 @TypeAnno("T1 field") @TypeAnno2("T2 field") T field1; 410 T field2; 411 @TypeAnno("Object field") Object field3; 412 413 public @TypeAnno("t1") @TypeAnno2("t2") T foo(){ return null; } 414 public <M extends @TypeAnno("M Runnable") Runnable> M foo2() {return null;} 415 public <@TypeAnno("K") K extends Cloneable> K foo3() {return null;} 416 } 417 418 @Target(ElementType.TYPE_USE) 419 @Retention(RetentionPolicy.RUNTIME) 420 @interface TypeAnno { 421 String value(); 422 } 423 424 @Target(ElementType.TYPE_USE) 425 @Retention(RetentionPolicy.RUNTIME) 426 @interface TypeAnno2 { 427 String value(); 428 }