< prev index next >

test/jdk/java/lang/annotation/typeAnnotations/TestObjectMethods.java

Print this page




   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 8058202
  27  * @summary Test java.lang.Object methods on AnnotatedType objects.
  28  */
  29 
  30 import java.lang.annotation.*;
  31 import java.lang.reflect.*;
  32 import java.util.*;

  33 
  34 /**
  35  * Test toString, equals, and hashCode on various AnnotatedType objects.
  36  */

  37 public class TestObjectMethods {
  38     private static int errors = 0;
  39 
  40     /*
  41      * There are various subtypes of AnnotatedType implementations:
  42      *
  43      * AnnotatedType
  44      * AnnotatedArrayType
  45      * AnnotatedParameterizedType
  46      * AnnotatedTypeVariable
  47      * AnnotatedWildcardType
  48      *
  49      * The implementations of each these implementations are
  50      * examined. Wildcards don't appear as top-level types and need to
  51      * be extracted from bounds.
  52      *
  53      * AnnotatedTypes with and without annotations are examined as
  54      * well.
  55      */
  56     public static void main(String... args) {
  57         Class<?>[] testClasses = {TypeHost.class, AnnotatedTypeHost.class};
  58 
  59         for (Class<?> clazz : testClasses) {
  60             testEqualsReflexivity(clazz);
  61             testEquals(clazz);
  62         }
  63 
  64         testToString(TypeHost.class, false);
  65         testToString(AnnotatedTypeHost.class, true);
  66 
  67         testAnnotationsMatterForEquals(TypeHost.class, AnnotatedTypeHost.class);
  68 
  69         testGetAnnotations(TypeHost.class, false);
  70         testGetAnnotations(AnnotatedTypeHost.class, true);
  71 
  72         testWildcards();
  73 
  74         if (errors > 0) {
  75             throw new RuntimeException(errors + " errors");
  76         }
  77     }
  78 
  79     /*
  80      * For non-array types, verify toString version of the annotated
  81      * type ends with the same string as the generic type.
  82      */
  83     static void testToString(Class<?> clazz, boolean leadingAnnotations) {
  84         System.err.println("Testing toString on methods of class " + clazz.getName());
  85         Method[] methods = clazz.getDeclaredMethods();
  86         for (Method m : methods) {






  87             AnnotatedType annotType = m.getAnnotatedReturnType();
  88             String annotTypeString = annotType.toString();
  89 
  90             Type type = m.getGenericReturnType();
  91             String typeString = type.toString();


  92 
  93             boolean isArray = annotType instanceof AnnotatedArrayType;
  94             boolean isVoid = "void".equals(typeString);
  95 
  96             boolean valid;
  97             if (!isArray) {
  98                 if (leadingAnnotations && !isVoid) {
  99                     valid =
 100                         annotTypeString.endsWith(typeString) &&
 101                         !annotTypeString.startsWith(typeString);
 102                 } else {
 103                     valid = annotTypeString.equals(typeString);
 104                 }
 105             } else {











 106                 // Find final non-array component type and gets its name.
 107                 typeString = null;
 108 
 109                 AnnotatedType componentType = annotType;
 110                 while (componentType instanceof AnnotatedArrayType) {
 111                     AnnotatedArrayType annotatedArrayType = (AnnotatedArrayType) componentType;
 112                     componentType = annotatedArrayType.getAnnotatedGenericComponentType();
 113                 }
 114 
 115                 String componentName = componentType.getType().getTypeName();
 116                 valid = annotTypeString.contains(componentName);



























 117             }
 118 
 119             if (!valid) {
 120                 errors++;
 121                 System.err.println(typeString + "\n" + annotTypeString +
 122                                    "\n " + valid  +
 123                                    "\n\n");
 124             }
 125         }
 126     }
 127 


 128     static void testGetAnnotations(Class<?> clazz, boolean annotationsExpectedOnMethods) {
 129         System.err.println("Testing getAnnotations on methods of class " + clazz.getName());
 130         Method[] methods = clazz.getDeclaredMethods();
 131         for (Method m : methods) {
 132             Type type = m.getGenericReturnType();
 133             AnnotatedType annotType = m.getAnnotatedReturnType();
 134             Annotation[] annotations = annotType.getAnnotations();
 135 
 136             boolean isVoid = "void".equals(type.toString());
 137 
 138             if (annotationsExpectedOnMethods && !isVoid) {
 139                 if (annotations.length == 0 ) {
 140                     errors++;
 141                     System.err.println("Expected annotations missing on " + annotType);
 142                 }
 143             } else {
 144                 if (annotations.length > 0 ) {
 145                     errors++;
 146                     System.err.println("Unexpected annotations present on " + annotType);
 147                 }


 213         System.err.println("Testing that presence/absence of annotations matters for equals comparison.");
 214 
 215         String methodName = null;
 216         for (Method method :  clazz1.getDeclaredMethods()) {
 217             if ("void".equals(method.getReturnType().toString())) {
 218                 continue;
 219             }
 220 
 221             methodName = method.getName();
 222             try {
 223                 checkTypesForEquality(method.getAnnotatedReturnType(),
 224                                       clazz2.getDeclaredMethod(methodName).getAnnotatedReturnType(),
 225                                       false);
 226             } catch (Exception e) {
 227                 errors++;
 228                 System.err.println("Method " + methodName + " not found.");
 229             }
 230         }
 231     }
 232 
 233 
 234     static void testWildcards() {
 235         System.err.println("Testing wildcards");
 236         // public @AnnotType(10) Set<? extends Number> fooNumberSet() {return null;}
 237         // public @AnnotType(11) Set<@AnnotType(13) ? extends Number> fooNumberSet2() {return null;}
 238         AnnotatedWildcardType awt1 = extractWildcard("fooNumberSet");
 239         AnnotatedWildcardType awt2 = extractWildcard("fooNumberSet2");
 240 
 241         if (!awt1.equals(extractWildcard("fooNumberSet")) ||
 242             !awt2.equals(extractWildcard("fooNumberSet2"))) {
 243             errors++;
 244             System.err.println("Bad equality comparison on wildcards.");
 245         }
 246 
 247         checkTypesForEquality(awt1, awt2, false);
 248 
 249         if (awt2.getAnnotations().length == 0) {
 250             errors++;
 251             System.err.println("Expected annotations not found.");
 252         }
 253     }
 254 
 255     private static AnnotatedWildcardType extractWildcard(String methodName) {
 256         try {
 257             return (AnnotatedWildcardType)
 258                 (((AnnotatedParameterizedType)(AnnotatedTypeHost.class.getMethod(methodName).
 259                                                getAnnotatedReturnType())).
 260                  getAnnotatedActualTypeArguments()[0] );
 261         } catch (Exception e) {
 262             throw new RuntimeException(e);
 263         }
 264     }
 265 
 266     // The TypeHost and AnnotatedTypeHost classes declare methods with
 267     // the same name and signatures but with the AnnotatedTypeHost
 268     // methods having annotations on their return type, where
 269     // possible.
 270 
 271     static class TypeHost<E, F extends Number> {

 272         public void fooVoid() {return;}
 273 

 274         public int foo() {return 0;}


 275         public String fooString() {return null;}
 276 

 277         public int[] fooIntArray() {return null;}


 278         public String[] fooStringArray() {return null;}


 279         public String [][] fooStringArrayArray() {return null;}
 280 

 281         public Set<String> fooSetString() {return null;}





 282         public E fooE() {return null;}


 283         public F fooF() {return null;}


 284         public <G> G fooG() {return null;}
 285 

 286         public  Set<? extends Number> fooNumberSet() {return null;}


 287         public  Set<? extends Integer> fooNumberSet2() {return null;}



 288     }
 289 
 290     @Retention(RetentionPolicy.RUNTIME)
 291     @Target(ElementType.TYPE_USE)
 292     static @interface AnnotType {
 293         int value() default 0;
 294     }
 295 









































 296     static class AnnotatedTypeHost<E, F extends Number> {

 297         public /*@AnnotType(0)*/ void fooVoid() {return;} // Illegal to annotate void
 298 
 299         public @AnnotType(1) int foo() {return 0;}
 300         public @AnnotType(2) String fooString() {return null;}





 301 

 302         public  int @AnnotType(3) [] fooIntArray() {return null;}


 303         public  String @AnnotType(4) [] fooStringArray() {return null;}
 304         public  @AnnotType(5) String  @AnnotType(0) [] @AnnotType(1) [] fooStringArrayArray() {return null;}
 305 
 306         public @AnnotType(6) Set<String> fooSetString() {return null;}
 307         public @AnnotType(7) E fooE() {return null;}
 308         public @AnnotType(8) F fooF() {return null;}
 309         public @AnnotType(9) <G> G fooG() {return null;}























 310 
 311         public @AnnotType(10) Set<? extends Number> fooNumberSet() {return null;}
 312         public @AnnotType(11) Set<@AnnotType(13) ? extends Number> fooNumberSet2() {return null;}





 313     }
 314 }


   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 8058202 8212081
  27  * @summary Test java.lang.Object methods on AnnotatedType objects.
  28  */
  29 
  30 import java.lang.annotation.*;
  31 import java.lang.reflect.*;
  32 import java.util.*;
  33 import java.util.regex.*;
  34 
  35 /**
  36  * Test toString, equals, and hashCode on various AnnotatedType objects.
  37  */
  38 
  39 public class TestObjectMethods {
  40     private static int errors = 0;
  41 
  42     /*
  43      * There are various subtypes of AnnotatedType implementations:
  44      *
  45      * AnnotatedType
  46      * AnnotatedArrayType
  47      * AnnotatedParameterizedType
  48      * AnnotatedTypeVariable
  49      * AnnotatedWildcardType
  50      *
  51      * The implementations of each these implementations are
  52      * examined. Wildcards don't appear as top-level types and need to
  53      * be extracted from bounds.
  54      *
  55      * AnnotatedTypes with and without annotations are examined as
  56      * well.
  57      */
  58     public static void main(String... args) {
  59         Class<?>[] testClasses = {TypeHost.class, AnnotatedTypeHost.class};
  60 
  61         for (Class<?> clazz : testClasses) {
  62             testEqualsReflexivity(clazz);
  63             testEquals(clazz);
  64         }
  65 
  66         testToString(TypeHost.class);
  67         testToString(AnnotatedTypeHost.class);
  68 
  69         testAnnotationsMatterForEquals(TypeHost.class, AnnotatedTypeHost.class);
  70 
  71         testGetAnnotations(TypeHost.class, false);
  72         testGetAnnotations(AnnotatedTypeHost.class, true);
  73 
  74         testWildcards();
  75 
  76         if (errors > 0) {
  77             throw new RuntimeException(errors + " errors");
  78         }
  79     }
  80 
  81     /*
  82      * For non-array types, verify toString version of the annotated
  83      * type ends with the same string as the generic type.
  84      */
  85     static void testToString(Class<?> clazz) {
  86         System.err.println("Testing toString on methods of class " + clazz.getName());
  87         Method[] methods = clazz.getDeclaredMethods();
  88         for (Method m : methods) {
  89             // Expected information about the type annotations stored
  90             // in a *declaration* annotation.
  91             AnnotTypeInfo annotTypeInfo = m.getAnnotation(AnnotTypeInfo.class);
  92             int expectedAnnotCount      = annotTypeInfo.count();
  93             Relation relation           = annotTypeInfo.relation();
  94 
  95             AnnotatedType annotType = m.getAnnotatedReturnType();
  96             String annotTypeString = annotType.toString();
  97 
  98             Type type = m.getGenericReturnType();
  99             String typeString = (type instanceof Class) ?
 100                 type.getTypeName() :
 101                 type.toString();
 102 
 103             boolean isArray = annotType instanceof AnnotatedArrayType;
 104             boolean isVoid = "void".equals(typeString);
 105 
 106             boolean valid;
 107 
 108             switch(relation) {
 109             case EQUAL:



 110                 valid = annotTypeString.equals(typeString);
 111                 break;
 112 
 113             case POSTFIX:
 114                 valid = annotTypeString.endsWith(typeString) &&
 115                     !annotTypeString.startsWith(typeString);
 116                 break;
 117 
 118             case STRIPPED:
 119                 String stripped = annotationRegex.matcher(annotTypeString).replaceAll("");
 120                 valid = typeString.replace(" ", "").equals(stripped.replace(" ", ""));
 121                 break;
 122 
 123             case ARRAY:
 124                 // Find final non-array component type and gets its name.
 125                 typeString = null;
 126 
 127                 AnnotatedType componentType = annotType;
 128                 while (componentType instanceof AnnotatedArrayType) {
 129                     AnnotatedArrayType annotatedArrayType = (AnnotatedArrayType) componentType;
 130                     componentType = annotatedArrayType.getAnnotatedGenericComponentType();
 131                 }
 132 
 133                 String componentName = componentType.getType().getTypeName();
 134                 valid = annotTypeString.contains(componentName);
 135                 break;
 136 
 137             default:
 138                 throw new AssertionError("Shouldn't be reached");
 139             }
 140 
 141             // Verify number of type annotations matches expected value
 142             Matcher matcher = annotationRegex.matcher(annotTypeString);
 143             if (expectedAnnotCount > 0) {
 144                 int i = expectedAnnotCount;
 145                 int annotCount = 0;
 146                 while (i > 0) {
 147                     boolean found = matcher.find();
 148                     if (found) {
 149                         i--;
 150                         annotCount++;
 151                     } else {
 152                         errors++;
 153                         System.err.println("\tExpected annotation not found: " + annotTypeString);
 154                     }
 155                 }
 156             }
 157 
 158             boolean found = matcher.find();
 159             if (found) {
 160                 errors++;
 161                 System.err.println("\tAnnotation found unexpectedly: " + annotTypeString);
 162             }
 163 
 164             if (!valid) {
 165                 errors++;
 166                 System.err.println(typeString + "\n" + annotTypeString +
 167                                    "\n " + valid  +
 168                                    "\n\n");
 169             }
 170         }
 171     }
 172 
 173     private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\$AnnotType\\(value=(\\p{Digit})+\\)");
 174 
 175     static void testGetAnnotations(Class<?> clazz, boolean annotationsExpectedOnMethods) {
 176         System.err.println("Testing getAnnotations on methods of class " + clazz.getName());
 177         Method[] methods = clazz.getDeclaredMethods();
 178         for (Method m : methods) {
 179             Type type = m.getGenericReturnType();
 180             AnnotatedType annotType = m.getAnnotatedReturnType();
 181             Annotation[] annotations = annotType.getAnnotations();
 182 
 183             boolean isVoid = "void".equals(type.toString());
 184 
 185             if (annotationsExpectedOnMethods && !isVoid) {
 186                 if (annotations.length == 0 ) {
 187                     errors++;
 188                     System.err.println("Expected annotations missing on " + annotType);
 189                 }
 190             } else {
 191                 if (annotations.length > 0 ) {
 192                     errors++;
 193                     System.err.println("Unexpected annotations present on " + annotType);
 194                 }


 260         System.err.println("Testing that presence/absence of annotations matters for equals comparison.");
 261 
 262         String methodName = null;
 263         for (Method method :  clazz1.getDeclaredMethods()) {
 264             if ("void".equals(method.getReturnType().toString())) {
 265                 continue;
 266             }
 267 
 268             methodName = method.getName();
 269             try {
 270                 checkTypesForEquality(method.getAnnotatedReturnType(),
 271                                       clazz2.getDeclaredMethod(methodName).getAnnotatedReturnType(),
 272                                       false);
 273             } catch (Exception e) {
 274                 errors++;
 275                 System.err.println("Method " + methodName + " not found.");
 276             }
 277         }
 278     }
 279 

 280     static void testWildcards() {
 281         System.err.println("Testing wildcards");
 282         // public @AnnotType(10) Set<? extends Number> fooNumberSet() {return null;}
 283         // public @AnnotType(11) Set<@AnnotType(13) ? extends Number> fooNumberSet2() {return null;}
 284         AnnotatedWildcardType awt1 = extractWildcard("fooNumberSet");
 285         AnnotatedWildcardType awt2 = extractWildcard("fooNumberSet2");
 286 
 287         if (!awt1.equals(extractWildcard("fooNumberSet")) ||
 288             !awt2.equals(extractWildcard("fooNumberSet2"))) {
 289             errors++;
 290             System.err.println("Bad equality comparison on wildcards.");
 291         }
 292 
 293         checkTypesForEquality(awt1, awt2, false);
 294 
 295         if (awt2.getAnnotations().length == 0) {
 296             errors++;
 297             System.err.println("Expected annotations not found.");
 298         }
 299     }
 300 
 301     private static AnnotatedWildcardType extractWildcard(String methodName) {
 302         try {
 303             return (AnnotatedWildcardType)
 304                 (((AnnotatedParameterizedType)(AnnotatedTypeHost.class.getMethod(methodName).
 305                                                getAnnotatedReturnType())).
 306                  getAnnotatedActualTypeArguments()[0] );
 307         } catch (Exception e) {
 308             throw new RuntimeException(e);
 309         }
 310     }
 311 
 312     // The TypeHost and AnnotatedTypeHost classes declare methods with
 313     // the same name and signatures but with the AnnotatedTypeHost
 314     // methods having annotations on their return type, where
 315     // possible.
 316 
 317     static class TypeHost<E, F extends Number> {
 318         @AnnotTypeInfo
 319         public void fooVoid() {return;}
 320 
 321         @AnnotTypeInfo
 322         public int foo() {return 0;}
 323 
 324         @AnnotTypeInfo
 325         public String fooString() {return null;}
 326 
 327         @AnnotTypeInfo
 328         public int[] fooIntArray() {return null;}
 329 
 330         @AnnotTypeInfo
 331         public String[] fooStringArray() {return null;}
 332 
 333         @AnnotTypeInfo
 334         public String [][] fooStringArrayArray() {return null;}
 335 
 336         @AnnotTypeInfo
 337         public Set<String> fooSetString() {return null;}
 338 
 339         @AnnotTypeInfo
 340         public Set<Number> fooSetNumber() {return null;}
 341 
 342         @AnnotTypeInfo
 343         public E fooE() {return null;}
 344 
 345         @AnnotTypeInfo
 346         public F fooF() {return null;}
 347 
 348         @AnnotTypeInfo
 349         public <G> G fooG() {return null;}
 350 
 351         @AnnotTypeInfo
 352         public  Set<? extends Number> fooNumberSet() {return null;}
 353 
 354         @AnnotTypeInfo
 355         public  Set<? extends Integer> fooNumberSet2() {return null;}
 356         
 357         @AnnotTypeInfo
 358         public  Set<? extends Long> fooNumberSet3() {return null;}
 359     }
 360 
 361     @Retention(RetentionPolicy.RUNTIME)
 362     @Target(ElementType.TYPE_USE)
 363     static @interface AnnotType {
 364         int value() default 0;
 365     }
 366 
 367     @Retention(RetentionPolicy.RUNTIME)
 368     @Target(ElementType.METHOD)
 369     static @interface AnnotTypeInfo {
 370         /**
 371          * Expected number of @AnnotType 
 372          */
 373         int count() default 0;
 374 
 375         /**
 376          * Relation to genericString output.
 377          */
 378         Relation relation() default Relation.EQUAL;
 379     }
 380     
 381     /**
 382      * Expected relationship of toString output of AnnotatedType to
 383      * toGenericString output of underlying type.
 384      */
 385     static private enum Relation {
 386         EQUAL,
 387 
 388         /**
 389          * The toGenericString output is a postfix of the
 390          * AnnotatedType output; a leading annotation is expected.
 391          */
 392         POSTFIX,
 393 
 394         /**
 395          * If the annotations are stripped from the AnnotatedType
 396          * output and whitespace adjusted accordingly, it should equal
 397          * the toGenericString output.
 398          */
 399         STRIPPED,
 400 
 401         /**
 402          * The output of AnnotatedType for arrays would require more
 403          * extensive transformation to map to toGenericString output.
 404          */
 405         ARRAY;
 406     }
 407 
 408     static class AnnotatedTypeHost<E, F extends Number> {
 409         @AnnotTypeInfo
 410         public /*@AnnotType(0)*/ void fooVoid() {return;} // Illegal to annotate void
 411 
 412         @AnnotTypeInfo(count =1, relation = Relation.POSTFIX)
 413         @AnnotType(1)
 414         public int foo() {return 0;}
 415 
 416         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 417         @AnnotType(2)
 418         public  String fooString() {return null;}
 419 
 420         @AnnotTypeInfo(count = 1, relation = Relation.ARRAY)
 421         public int @AnnotType(3) [] fooIntArray() {return null;}
 422         
 423         @AnnotTypeInfo(count = 1, relation = Relation.ARRAY)
 424         public String @AnnotType(4) [] fooStringArray() {return null;}

 425 
 426         @AnnotTypeInfo(count = 3, relation = Relation.ARRAY)
 427         @AnnotType(5)
 428         public String  @AnnotType(0) [] @AnnotType(1) [] fooStringArrayArray() {return null;}
 429 
 430         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 431         @AnnotType(6)
 432         public Set<String> fooSetString() {return null;}
 433         
 434         @AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
 435         @AnnotType(7)
 436         public Set<@AnnotType(8) Number> fooSetNumber() {return null;}
 437 
 438         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 439         @AnnotType(9)
 440         public E fooE() {return null;}
 441 
 442         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 443         @AnnotType(10)
 444         public F fooF() {return null;}
 445 
 446         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 447         @AnnotType(11)
 448         public <G> G fooG() {return null;}
 449 
 450         @AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
 451         @AnnotType(12)
 452         public Set<? extends Number> fooNumberSet() {return null;}
 453 
 454         @AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
 455         @AnnotType(13)
 456         public Set<@AnnotType(14) ? extends Number> fooNumberSet2() {return null;}
 457 
 458         @AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
 459         @AnnotType(15)
 460         public Set< ? extends @AnnotType(16) Long> fooNumberSet3() {return null;}
 461     }
 462 }
< prev index next >