1 /*
   2  * Copyright (c) 2007, 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  * @summary Tests com.sun.beans.TypeResolver
  27  * @author Eamonn McManus
  28  */
  29 
  30 import com.sun.beans.TypeResolver;
  31 
  32 import java.lang.annotation.Annotation;
  33 import java.lang.reflect.AnnotatedType;
  34 import java.lang.reflect.Field;
  35 import java.lang.reflect.GenericDeclaration;
  36 import java.lang.reflect.Method;
  37 import java.lang.reflect.Type;
  38 import java.lang.reflect.TypeVariable;
  39 import java.lang.reflect.WildcardType;
  40 import java.util.ArrayList;
  41 import java.util.Arrays;
  42 import java.util.Comparator;
  43 import java.util.List;
  44 import java.util.Map;
  45 
  46 import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
  47 import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
  48 
  49 public class TestTypeResolver {
  50     static final List<Class<?>> failedCases = new ArrayList<Class<?>>();
  51 
  52     public static void main(String[] args) throws Exception {
  53         test(TestTypeResolver.class);
  54         if (failedCases.isEmpty())
  55             System.out.println("TEST PASSED");
  56         else {
  57             System.out.println("TEST FAILED: failed cases: " + failedCases);
  58             throw new Error("TEST FAILED");
  59         }
  60     }
  61 
  62     private static void test(Class<?> c) throws Exception {
  63         /* Every public nested class represents a test.  In each case, either
  64          * the class contains further nested classes, in which case we
  65          * call this method recursively; or it declares or inherits a
  66          * method called getThing() and it declares a static field
  67          * called "expect" which
  68          * is the Type of that method's return value.  The test consists
  69          * of checking that the value returned by
  70          * TypeResolver.resolveInClass is indeed this Type.
  71          */
  72         System.out.println("Test " + c);
  73         Class<?>[] nested = c.getClasses();
  74         Arrays.sort(nested, classNameComparator);
  75         for (Class<?> n : nested)
  76             test(n);
  77         final Method m;
  78         try {
  79             m = c.getMethod("getThing");
  80         } catch (NoSuchMethodException e) {
  81             if (nested.length == 0) {
  82                 System.out.println(
  83                         "TEST ERROR: class " + c.getName() + " has neither " +
  84                                 "nested classes nor getThing() method");
  85                 failedCases.add(c);
  86             }
  87             return;
  88         }
  89         Object expect = null;
  90         try {
  91             Field f = c.getDeclaredField("expect");
  92             expect = f.get(null);
  93         } catch (NoSuchFieldException e) {
  94             Class<?> outer = c.getDeclaringClass();
  95             if (outer != null) {
  96                 try {
  97                     Field f = outer.getDeclaredField("expect" + c.getSimpleName());
  98                     expect = f.get(null);
  99                 } catch (NoSuchFieldException e1) {
 100                 }
 101             }
 102         }
 103         if (expect == null) {
 104             System.out.println(
 105                     "TEST ERROR: class " + c.getName() + " has getThing() method " +
 106                             "but not expect field");
 107             failedCases.add(c);
 108             return;
 109         }
 110         Type t = m.getGenericReturnType();
 111 //        t = FixType.fixType(t, c);
 112         t = TypeResolver.resolveInClass(c, t);
 113         System.out.print("..." + t);
 114         // check expected value, and incidentally equals method defined
 115         // by private implementations of the various Type interfaces
 116         if (expect.equals(t) && t.equals(expect))
 117             System.out.println(", as expected");
 118         else if ((expect.equals(t) || t.equals(expect)) && expect.toString().equals(t.toString()))
 119             System.out.println(", as workaround of the 8023301 bug");
 120         else {
 121             System.out.println(" BUT SHOULD BE " + expect);
 122             failedCases.add(c);
 123         }
 124     }
 125 
 126     private static class ClassNameComparator implements Comparator<Class<?>> {
 127         public int compare(Class<?> a, Class<?> b) {
 128             return a.getName().compareTo(b.getName());
 129         }
 130     }
 131 
 132     private static final Comparator<Class<?>> classNameComparator =
 133             new ClassNameComparator();
 134 
 135     private static abstract class TypeVariableImpl<D extends GenericDeclaration>
 136             implements TypeVariable<D> {
 137         private final String name;
 138         private final D gd;
 139         private final Type[] bounds;
 140 
 141         TypeVariableImpl(String name, D gd, Type... bounds) {
 142             this.name = name;
 143             this.gd = gd;
 144             if (bounds.length == 0)
 145                 bounds = new Type[] {Object.class};
 146             this.bounds = bounds.clone();
 147         }
 148 
 149         public Type[] getBounds() {
 150             return bounds.clone();
 151         }
 152 
 153         public D getGenericDeclaration() {
 154             return gd;
 155         }
 156 
 157         public String getName() {
 158             return name;
 159         }
 160 
 161         public String toString() {
 162             return name;
 163         }
 164 
 165         public boolean equals(Object o) {
 166             if (!(o instanceof TypeVariable))
 167                 return false;
 168             TypeVariable tv = (TypeVariable) o;
 169             return equal(name, tv.getName()) &&
 170                     equal(gd, tv.getGenericDeclaration()) &&
 171                     Arrays.equals(bounds, tv.getBounds());
 172         }
 173 
 174         public int hashCode() {
 175             return hash(name) ^ hash(gd) ^ Arrays.hashCode(bounds);
 176         }
 177 
 178         public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
 179             return false; // not used
 180         }
 181 
 182         public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 183             return null; // not used
 184         }
 185 
 186         public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) {
 187             return null; // not used
 188         }
 189 
 190         public Annotation[] getAnnotations() {
 191             return null; // not used
 192         }
 193 
 194         public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
 195             return null; // not used
 196         }
 197 
 198         public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) {
 199             return null; // not used
 200         }
 201 
 202         public Annotation[] getDeclaredAnnotations() {
 203             return null; // not used
 204         }
 205 
 206         public AnnotatedType[] getAnnotatedBounds() {
 207             return null; // not used
 208         }
 209 
 210         public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
 211             return null; // not used
 212         }
 213 
 214         public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
 215             return null; // not used
 216         }
 217 
 218     }
 219 
 220     private static class ClassTypeVariable extends TypeVariableImpl<Class<?>> {
 221         ClassTypeVariable(String name, Class<?> gd, Type... bounds) {
 222             super(name, gd, bounds);
 223         }
 224     }
 225 
 226     private static class MethodTypeVariable extends TypeVariableImpl<Method> {
 227         MethodTypeVariable(String name, Method gd, Type... bounds) {
 228             super(name, gd, bounds);
 229         }
 230     }
 231 
 232     private static class WildcardTypeImpl implements WildcardType {
 233         private final Type[] upperBounds;
 234         private final Type[] lowerBounds;
 235 
 236         WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
 237             if (upperBounds == null || upperBounds.length == 0)
 238                 upperBounds = new Type[] {Object.class};
 239             if (lowerBounds == null)
 240                 lowerBounds = new Type[0];
 241             this.upperBounds = upperBounds.clone();
 242             this.lowerBounds = lowerBounds.clone();
 243         }
 244 
 245         public Type[] getUpperBounds() {
 246             return upperBounds.clone();
 247         }
 248 
 249         public Type[] getLowerBounds() {
 250             return lowerBounds.clone();
 251         }
 252 
 253         public boolean equals(Object o) {
 254             if (o instanceof WildcardType) {
 255                 WildcardType wt = (WildcardType) o;
 256                 return Arrays.equals(upperBounds, wt.getUpperBounds()) &&
 257                         Arrays.equals(lowerBounds, wt.getLowerBounds());
 258             } else
 259                 return false;
 260         }
 261 
 262         public int hashCode() {
 263             return Arrays.hashCode(upperBounds) ^ Arrays.hashCode(lowerBounds);
 264         }
 265 
 266         public String toString() {
 267             StringBuilder sb = new StringBuilder("?");
 268             if (upperBounds.length > 1 || upperBounds[0] != Object.class) {
 269                 sb.append(" extends");
 270                 appendBounds(sb, upperBounds);
 271             }
 272             if (lowerBounds.length > 0) {
 273                 sb.append(" super");
 274                 appendBounds(sb, lowerBounds);
 275             }
 276             return sb.toString();
 277         }
 278 
 279         private static void appendBounds(StringBuilder sb, Type[] bounds) {
 280             boolean and = false;
 281             for (Type bound : bounds) {
 282                 if (and)
 283                     sb.append(" &");
 284                 sb.append(" ");
 285                 if (bound instanceof Class)
 286                     sb.append(((Class<?>) bound).getName());
 287                 else
 288                     sb.append(bound);
 289                 and = true;
 290             }
 291         }
 292     }
 293 
 294     static boolean equal(Object x, Object y) {
 295         if (x == y)
 296             return true;
 297         if (x == null || y == null)
 298             return false;
 299         return x.equals(y);
 300     }
 301 
 302     static int hash(Object x) {
 303         return (x == null) ? null : x.hashCode();
 304     }
 305 
 306 
 307     public static class Outer<T> {
 308         public class Inner {
 309             public T getThing() {
 310                 return null;
 311             }
 312         }
 313 
 314         static final Type expectInner = new ClassTypeVariable("T", Outer.class);
 315     }
 316 
 317     public static class Super<T> {
 318         static final Type expect = new ClassTypeVariable("T", Super.class);
 319 
 320         public T getThing() {
 321             return null;
 322         }
 323     }
 324 
 325     public static class Int extends Super<Integer> {
 326         static final Type expect = Integer.class;
 327     }
 328 
 329     public static class IntOverride extends Int {
 330         static final Type expect = Integer.class;
 331 
 332         public Integer getThing() {
 333             return null;
 334         }
 335     }
 336 
 337     public static class Mid<X> extends Super<X> {
 338         static final Type expect = new ClassTypeVariable("X", Mid.class);
 339     }
 340 
 341     public static class Str extends Mid<String> {
 342         static final Type expect = String.class;
 343     }
 344 
 345     public static class ListInt extends Super<List<Integer>> {
 346         static final Type expect = ParameterizedTypeImpl.make(
 347                 List.class, new Type[] {Integer.class}, null);
 348     }
 349 
 350     public static class ListIntSub extends ListInt {
 351         static final Type expect = ParameterizedTypeImpl.make(
 352                 List.class, new Type[] {Integer.class}, null);
 353 
 354         public List<Integer> getThing() {
 355             return null;
 356         }
 357     }
 358 
 359     public static class ListU<U> extends Super<List<U>> {
 360         static final Type expect = ParameterizedTypeImpl.make(
 361                 List.class, new Type[] {new ClassTypeVariable("U", ListU.class)}, null);
 362     }
 363 
 364     public static class ListUInt extends ListU<Integer> {
 365         static final Type expect = ParameterizedTypeImpl.make(
 366                 List.class, new Type[] {Integer.class}, null);
 367     }
 368 
 369     public static class ListUSub<V> extends ListU<V> {
 370         static final Type expect = ParameterizedTypeImpl.make(
 371                 List.class, new Type[] {new ClassTypeVariable("V", ListUSub.class)}, null);
 372 
 373         public List<V> getThing() {
 374             return null;
 375         }
 376     }
 377 
 378     public static class ListUSubInt extends ListUSub<Integer> {
 379         static final Type expect = ParameterizedTypeImpl.make(
 380                 List.class, new Type[] {Integer.class}, null);
 381     }
 382 
 383     public static class TwoParams<S, T> extends Super<S> {
 384         static final Type expect = new ClassTypeVariable("S", TwoParams.class);
 385     }
 386 
 387     public static class TwoParamsSub<T> extends TwoParams<T, Integer> {
 388         static final Type expect = new ClassTypeVariable("T", TwoParamsSub.class);
 389     }
 390 
 391     public static class TwoParamsSubSub extends TwoParamsSub<String> {
 392         static final Type expect = String.class;
 393     }
 394 
 395     public static interface Intf<T> {
 396         static final Type expect = new ClassTypeVariable("T", Intf.class);
 397 
 398         public T getThing();
 399     }
 400 
 401     public static abstract class Impl implements Intf<String> {
 402         static final Type expect = String.class;
 403     }
 404 
 405     public static class Impl2 extends Super<String> implements Intf<String> {
 406         static final Type expect = String.class;
 407     }
 408 
 409     public static class Bound<T extends Number> extends Super<T> {
 410         static final Type expect = new ClassTypeVariable("T", Bound.class, Number.class);
 411     }
 412 
 413     public static class BoundInt extends Bound<Integer> {
 414         static final Type expect = Integer.class;
 415     }
 416 
 417     public static class RawBound extends Bound {
 418         static final Type expect = Number.class;
 419     }
 420 
 421     public static class RawBoundInt extends BoundInt {
 422         static final Type expect = Integer.class;
 423     }
 424 
 425     public static class MethodParam<T> {
 426         private static final Method m;
 427 
 428         static {
 429             try {
 430                 m = MethodParam.class.getMethod("getThing");
 431             } catch (Exception e) {
 432                 throw new AssertionError(e);
 433             }
 434         }
 435 
 436         static final Type expect = new MethodTypeVariable("T", m);
 437 
 438         public <T> T getThing() {
 439             return null;
 440         }
 441     }
 442 
 443     public static class Raw extends Super {
 444         static final Type expect = Object.class;
 445     }
 446 
 447     public static class RawSub extends Raw {
 448         static final Type expect = Object.class;
 449     }
 450 
 451     public static class SimpleArray extends Super<String[]> {
 452         static final Type expect = String[].class;
 453     }
 454 
 455     public static class GenericArray extends Super<List<String>[]> {
 456         static final Type expect = GenericArrayTypeImpl.make(
 457                 ParameterizedTypeImpl.make(List.class, new Type[] {String.class}, null));
 458     }
 459 
 460     public static class GenericArrayT<T> extends Super<T[]> {
 461         static final Type expect = GenericArrayTypeImpl.make(
 462                 new ClassTypeVariable("T", GenericArrayT.class));
 463     }
 464 
 465     public static class GenericArrayTSub extends GenericArrayT<String[]> {
 466         static final Type expect = String[][].class;
 467     }
 468 
 469     public static class Wildcard extends Super<List<?>> {
 470         static final Type expect = ParameterizedTypeImpl.make(
 471                 List.class, new Type[] {new WildcardTypeImpl(null, null)}, null);
 472     }
 473 
 474     public static class WildcardT<T> extends Super<List<? extends T>> {
 475         static final Type expect = ParameterizedTypeImpl.make(
 476                 List.class,
 477                 new Type[] {
 478                         new WildcardTypeImpl(
 479                                 new Type[] {new ClassTypeVariable("T", WildcardT.class)},
 480                                 null)},
 481                 null);
 482     }
 483 
 484     public static class WildcardTSub extends WildcardT<Integer> {
 485         static final Type expect = ParameterizedTypeImpl.make(
 486                 List.class,
 487                 new Type[] {
 488                         new WildcardTypeImpl(
 489                                 new Type[] {Integer.class},
 490                                 null)},
 491                 null);
 492     }
 493 
 494     public static class WildcardTSubSub<X> extends WildcardTSub {
 495         // X is just so we can have a raw subclass
 496         static final Type expect = WildcardTSub.expect;
 497     }
 498 
 499     public static class RawWildcardTSubSub extends WildcardTSubSub {
 500         static final Type expect = List.class;
 501     }
 502 
 503     public static class WildcardTSuper<T> extends Super<List<? super T>> {
 504         static final Type expect = ParameterizedTypeImpl.make(
 505                 List.class,
 506                 new Type[] {
 507                         new WildcardTypeImpl(
 508                                 null,
 509                                 new Type[] {new ClassTypeVariable("T", WildcardTSuper.class)})},
 510                 null);
 511     }
 512 
 513     public static class WildcardTSuperSub extends WildcardTSuper<Integer> {
 514         static final Type expect = ParameterizedTypeImpl.make(
 515                 List.class,
 516                 new Type[] {
 517                         new WildcardTypeImpl(
 518                                 null,
 519                                 new Type[] {Integer.class})},
 520                 null);
 521     }
 522 
 523     public static class SuperMap<K, V> {
 524         static final Type expect = ParameterizedTypeImpl.make(
 525                 Map.class,
 526                 new Type[] {
 527                         new ClassTypeVariable("K", SuperMap.class),
 528                         new ClassTypeVariable("V", SuperMap.class)},
 529                 null);
 530 
 531         public Map<K, V> getThing() {
 532             return null;
 533         }
 534     }
 535 
 536     public static class SubMap extends SuperMap<String, Integer> {
 537         static final Type expect = ParameterizedTypeImpl.make(
 538                 Map.class,
 539                 new Type[] {String.class, Integer.class},
 540                 null);
 541     }
 542 
 543     public static class ListListT<T> extends Super<List<List<T>>> {
 544         static final Type expect = ParameterizedTypeImpl.make(
 545                 List.class,
 546                 new Type[] {
 547                         ParameterizedTypeImpl.make(
 548                                 List.class,
 549                                 new Type[] {new ClassTypeVariable("T", ListListT.class)},
 550                                 null)},
 551                 null);
 552     }
 553 
 554     public static class ListListString extends ListListT<String> {
 555         static final Type expect = ParameterizedTypeImpl.make(
 556                 List.class,
 557                 new Type[] {
 558                         ParameterizedTypeImpl.make(
 559                                 List.class,
 560                                 new Type[] {String.class},
 561                                 null)},
 562                 null);
 563     }
 564 
 565     public static class UExtendsT<T, U extends T> extends Super<U> {
 566         static final Type expect = new ClassTypeVariable(
 567                 "U", UExtendsT.class, new ClassTypeVariable("T", UExtendsT.class));
 568     }
 569 
 570     public static class UExtendsTSub extends UExtendsT<Number, Integer> {
 571         static final Type expect = Integer.class;
 572     }
 573 
 574     public static class SelfRef<T extends SelfRef<T>> extends Super<T> {
 575         static final Type expect =
 576                 SelfRef.class.getTypeParameters()[0];
 577     }
 578 
 579     public static class SelfRefSub extends SelfRef<SelfRefSub> {
 580         static final Type expect = SelfRefSub.class;
 581     }
 582 }