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 }