1/*
2 * Copyright (c) 2014, 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 8039916
27 * @summary Test that a call to getType() on an AnnotatedType returned from an
28 *          Executable.getAnnotated* returns the same type as the corresponding
29 *          Executable.getGeneric* call.
30 * @run testng TestExecutableGetAnnotatedType
31 */
32
33import org.testng.annotations.DataProvider;
34import org.testng.annotations.Test;
35
36import java.lang.annotation.*;
37import java.lang.reflect.*;
38import java.util.Arrays;
39import java.util.List;
40import java.util.stream.Collectors;
41import java.util.stream.Stream;
42
43import static org.testng.Assert.*;
44
45public class TestExecutableGetAnnotatedType {
46    @Test(dataProvider = "genericExecutableData")
47    public void testGenericMethodExceptions(Executable e) throws Exception {
48        testExceptions(e);
49    }
50
51    @Test(dataProvider = "executableData")
52    public void testMethodExceptions(Executable e) throws Exception {
53        testExceptions(e);
54    }
55
56    @Test(dataProvider = "genericExecutableData")
57    public void testGenericMethodParameterTypes(Executable e) throws Exception {
58        testMethodParameters(e);
59    }
60
61    @Test(dataProvider = "executableData")
62    public void testMethodParameterTypes(Executable e) throws Exception {
63        testMethodParameters(e);
64    }
65
66    @Test(dataProvider = "genericExecutableData")
67    public void testGenericParameterTypes(Executable e) throws Exception {
68        testParameters(e.getParameters());
69    }
70
71    @Test(dataProvider = "executableData")
72    public void testParameterTypes(Executable e) throws Exception {
73        testParameters(e.getParameters());
74    }
75
76    @Test(dataProvider = "genericMethodData")
77    public void testGenericReceiverType(Executable e) throws Exception {
78        testReceiverType0(e);
79    }
80
81    @Test(dataProvider = "methodData")
82    public void testReceiverType(Executable e) throws Exception {
83        testReceiverType0(e);
84    }
85
86    @Test(dataProvider = "genericMethodData")
87    public void testGenericMethodReturnType(Object o) throws Exception {
88        // testng gets confused if the param to this method has type Method
89        Method m = (Method)o;
90        testReturnType(m);
91    }
92
93    @Test(dataProvider = "methodData")
94    public void testMethodReturnType(Object o) throws Exception {
95        // testng gets confused if the param to this method has type Method
96        Method m = (Method)o;
97        testReturnType(m);
98    }
99
100    private void testExceptions(Executable e) {
101        Type[] ts = e.getGenericExceptionTypes();
102        AnnotatedType[] ats = e.getAnnotatedExceptionTypes();
103        assertEquals(ts.length, ats.length);
104
105        for (int i = 0; i < ts.length; i++) {
106            Type t = ts[i];
107            AnnotatedType at = ats[i];
108            assertSame(at.getType(), t, e.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
109        }
110    }
111
112    private void testMethodParameters(Executable e) {
113        Type[] ts = e.getGenericParameterTypes();
114        AnnotatedType[] ats = e.getAnnotatedParameterTypes();
115        assertEquals(ts.length, ats.length);
116
117        for (int i = 0; i < ts.length; i++) {
118            Type t = ts[i];
119            AnnotatedType at = ats[i];
120            assertSame(at.getType(), t, e.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
121        }
122    }
123
124    private void testParameters(Parameter[] params) {
125        for (Parameter p : params) {
126            Type t = p.getParameterizedType();
127            AnnotatedType at = p.getAnnotatedType();
128            assertSame(at.getType(), t, p.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
129        }
130    }
131
132    private void testReceiverType0(Executable e) {
133        if (Modifier.isStatic(e.getModifiers()))
134            assertNull(e.getAnnotatedReceiverType());
135        else
136            assertSame(e.getAnnotatedReceiverType().getType(), e.getDeclaringClass());
137    }
138
139    private void testReturnType(Method m) {
140        Type t = m.getGenericReturnType();
141        AnnotatedType at = m.getAnnotatedReturnType();
142        assertSame(at.getType(), t, m.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
143    }
144
145    @DataProvider
146    public Object[][] methodData() throws Exception {
147        return filterData(Arrays.stream(Methods1.class.getMethods()), Methods1.class)
148            .toArray(new Object[0][0]);
149    }
150
151    @DataProvider
152    public Object[][] genericMethodData()  throws Exception {
153        return filterData(Arrays.stream(GenericMethods1.class.getMethods()), GenericMethods1.class)
154            .toArray(new Object[0][0]);
155    }
156
157    @DataProvider
158    public Object[][] executableData() throws Exception {
159    @SuppressWarnings("raw")
160        List l = filterData(Arrays.stream(Methods1.class.getMethods()), Methods1.class);
161        l.addAll(filterData(Arrays.stream(Methods1.class.getConstructors()), Methods1.class));
162        l.addAll(filterData(Arrays.stream(Ctors1.class.getConstructors()), Ctors1.class));
163        return ((List<Object[][]>)l).toArray(new Object[0][0]);
164    }
165
166    @DataProvider
167    public Object[][] genericExecutableData() throws Exception {
168    @SuppressWarnings("raw")
169        List l = filterData(Arrays.stream(GenericMethods1.class.getMethods()), GenericMethods1.class);
170        l.addAll(filterData(Arrays.stream(GenericMethods1.class.getConstructors()), GenericMethods1.class));
171        l.addAll(filterData(Arrays.stream(GenericCtors1.class.getConstructors()), GenericCtors1.class));
172        return ((List<Object[][]>)l).toArray(new Object[0][0]);
173    }
174
175    private List<?> filterData(Stream<? extends Executable> l, Class<?> c) {
176        return l.filter(m -> (m.getDeclaringClass() == c)) // remove object methods
177            .map(m -> { Object[] o = new Object[1]; o[0] = m; return o; })
178            .collect(Collectors.toList());
179    }
180
181    @Retention(RetentionPolicy.RUNTIME)
182    @Target(ElementType.TYPE_USE)
183    public @interface TA {}
184
185    @Retention(RetentionPolicy.RUNTIME)
186    @Target(ElementType.TYPE_USE)
187    public @interface TB {}
188
189    @Retention(RetentionPolicy.RUNTIME)
190    @Target(ElementType.TYPE_USE)
191    public @interface TC {}
192
193    public static class Methods1 {
194        public static void m1() throws Error, RuntimeException {;}
195        public static long m2(int a, double b) throws Error, RuntimeException { return 0L; }
196        public static Object m3(String s, List l) throws Error, RuntimeException { return null; }
197        public static Object m4(String s, List<String> l) { return null; }
198        public static Object m4(String s, List<String> l, boolean ... b){ return null; }
199
200        public static void m10() throws @TA Error, @TB @TC RuntimeException {;}
201        public static @TB long m20(@TC int a, @TA double b) throws @TA Error, @TB @TC RuntimeException { return 0L; }
202        public static @TC Object m30(@TA String s, @TB List l) throws @TA Error, @TB @TC RuntimeException { return null; }
203        public static @TA Object m40(@TB String s, @TC List<@TA String> l) { return null; }
204        public static @TA Object m40(@TB String s, @TC List<@TA String> l, @TB boolean ... b) { return null; }
205
206        public Methods1(int a, double b) {}
207        public Methods1(String s, List<String> l, boolean ... b) {}
208        public Methods1(@TC long a, @TA float b) {}
209        public Methods1(@TA int i, @TB String s, @TC List<@TA String> l, @TB boolean ... b) {}
210    }
211
212    // test default ctor
213    public static class Ctors1 {
214    }
215
216    public static class GenericMethods1<E> {
217        public E m1(E e, Object o) throws Error, RuntimeException { return null; }
218        public E m2(List<? extends List> e, int i) throws Error, RuntimeException { return null; }
219        public E m3(double d, List<E> e) throws Error, RuntimeException { return null; }
220        public <E extends List> E m4(byte[] b, GenericMethods1<? extends E> e) { return null; }
221        public <E extends List> E m5(GenericMethods1<? super Number> e) { return null; }
222        public <E extends List & Cloneable> E m6(char c, E e) { return null; }
223        public <E extends List & Cloneable> E m7(char c, E e, byte ... b) { return null; }
224
225        public static <M> M n1(M e) { return null; }
226        public static <M> M n2(List<? extends List> e) { return null; }
227        public static <M extends RuntimeException> M n3(List<M> e) throws Error, M { return null; }
228        public static <M extends Number> M n4(GenericMethods1<? extends M> e) throws Error, RuntimeException { return null; }
229        public static <M extends Object> M n5(GenericMethods1<? super Number> e) { return null; }
230        public static <M extends List & Cloneable> M n6(M e) { return null; }
231
232        public <M> E o1(E e) { return null; }
233        public <M> E o2(List<? extends List> e) { return null; }
234        public <M extends Error, N extends RuntimeException> E o3(GenericMethods1<E> this, List<E> e) throws M, N { return null; }
235        public <M extends Number> E o4(GenericMethods1<? extends E> e) throws Error, RuntimeException { return null; }
236        public <M extends Object> E o5(GenericMethods1<? super Number> e) { return null; }
237        public <M extends List & Cloneable> E o6(E e) { return null; }
238
239
240        // with annotations
241        public @TA E m10(E e, @TC Object o) throws @TA Error, @TB @TC RuntimeException { return null; }
242        public @TB E m20(@TA List<@TA ? extends @TA List> e, @TC int i) throws @TA Error, @TB @TC RuntimeException { return null; }
243        public @TB E m30(@TC double d, List<E> e) throws @TA Error, @TB @TC RuntimeException { return null; }
244        public <@TA E extends @TA List> @TA E m40(@TA byte @TB [] b, GenericMethods1<@TA ? extends E> e) { return null; }
245        public <@TB E extends @TB List> E m50(@TA GenericMethods1<? super Number> e) { return null; }
246        public <@TB E extends @TA List & Cloneable> E m60(@TC char c, E e) { return null; }
247        public <@TB E extends @TA List & Cloneable> E m70(@TC char c, E e, @TA @TB byte ... b) { return null; }
248
249        public static <@TA M> @TA M n10(M e) { return null; }
250        public static <@TA @TB @TC M> M n20(List<@TA ? extends List> e) { return null; }
251        @TA @TB @TC public static <M extends RuntimeException> M n30(List<@TB M> e) throws @TA Error, @TB @TC M { return null; }
252        public static <@TC M extends Number> M n40(GenericMethods1<? extends @TA M> e) throws @TA Error, @TB @TC RuntimeException { return null; }
253        @TA public static <M extends @TB Object> M n50(GenericMethods1<? super Number> e) { return null; }
254        public static <@TA M extends @TB List & @TC @TB Cloneable> M n60(M e) { return null; }
255
256        public <@TC M> E o10(@TA E e) { return null; }
257        public <M> @TA E o20(@TB List<@TB ? extends @TB List> e) { return null; }
258        @TC public <M extends Error, N extends RuntimeException> @TB E o30(@TA @TB @TC GenericMethods1<E> this, List<E> e) throws @TA M, @TB @TC N { return null; }
259        public <@TA M extends Number> E o40(GenericMethods1<? extends @TA E> e) throws @TA Error, @TB @TC RuntimeException { return null; }
260        public <M extends @TA Object> E o50(GenericMethods1<@TA ? super Number> e) { return null; }
261        public <@TA M extends @TB List & @TC Cloneable> E o60(@TA E e) { return null; }
262
263
264        // ctors
265        public GenericMethods1(List<? extends List> e, int i) throws Error, RuntimeException { }
266        public <E extends List & Cloneable> GenericMethods1(char c, E e, byte ... b) { }
267        @TC public <M extends Error, N extends RuntimeException> GenericMethods1(List<@TC E> e) throws @TA M, @TB @TC N { }
268        public <@TA M extends @TB List & @TC Cloneable> GenericMethods1(@TA E e, @TB M m) throws @TA Exception { }
269        public <@TA M extends @TB List & @TC Cloneable> GenericMethods1(@TA E e, @TB M m, @TC byte ... b) throws Exception { }
270    }
271
272    // test default ctor
273    public static class GenericCtors1<T> {
274    }
275}
276