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