1/*
2 * Copyright (c) 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 * @bug 8058595
27 * @summary Test that AnnotatedType.getAnnotatedOwnerType() works as expected
28 *
29 * @library /lib/testlibrary
30 * @build jdk.testlibrary.Asserts
31 * @run main GetAnnotatedOwnerType
32 */
33
34import java.lang.annotation.*;
35import java.lang.reflect.*;
36
37import jdk.testlibrary.Asserts;
38
39public class GetAnnotatedOwnerType<Dummy> {
40    public @TA("generic") GetAnnotatedOwnerType<String> . @TB("generic") Nested<Integer> genericField;
41    public @TA("raw") GetAnnotatedOwnerType . @TB("raw") Nested rawField;
42    public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("non-generic") Inner nonGeneric;
43    public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("generic") InnerGeneric<String> innerGeneric;
44    public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("raw") InnerGeneric innerRaw;
45    public Object anonymous = new Object() {};
46    public @TA("array") Dummy[] dummy;
47    public @TA("wildcard") GetAnnotatedOwnerType<?> wildcard;
48    public @TA("typevariable") Dummy tv;
49    public @TA("bad") GetAnnotatedOwnerType<@TA("good") GetAnnotatedOwnerType<String> . @TB("tb") Nested<Integer> >  typeArgument;
50    public GetAnnotatedOwnerType< GetAnnotatedOwnerType<String> .
51            B .
52            C<Class<?>, ? extends @TA("complicated") Exception> .
53            D<Number> > [] complicated;
54
55    public static void main(String[] args) throws Exception {
56        testGeneric();
57        testRaw();
58        testNonGeneric();
59        testInnerGeneric();
60        testInnerRaw();
61
62        testLocalClass();
63        testAnonymousClass();
64
65        testArray();
66        testWildcard();
67        testTypeParameter();
68
69        testTypeArgument();
70        testComplicated();
71    }
72
73    public static void testGeneric() throws Exception {
74        Field f = GetAnnotatedOwnerType.class.getField("genericField");
75
76        // make sure inner is correctly annotated
77        AnnotatedType inner = f.getAnnotatedType();
78        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
79        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
80                + inner.getAnnotations().length);
81
82        // make sure owner is correctly annotated, on the correct type
83        AnnotatedType outer = inner.getAnnotatedOwnerType();
84        Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
85        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "generic");
86        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
87                + outer.getAnnotations().length);
88    }
89
90    public static void testRaw() throws Exception {
91        Field f = GetAnnotatedOwnerType.class.getField("rawField");
92
93        // make sure inner is correctly annotated
94        AnnotatedType inner = f.getAnnotatedType();
95        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
96        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
97                + inner.getAnnotations().length);
98
99        // make sure owner is correctly annotated, on the correct type
100        AnnotatedType outer = inner.getAnnotatedOwnerType();
101        Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
102        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "raw");
103        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
104                + outer.getAnnotations().length);
105    }
106
107    public static void testNonGeneric() throws Exception {
108        Field f = GetAnnotatedOwnerType.class.getField("nonGeneric");
109
110        // make sure inner is correctly annotated
111        AnnotatedType inner = f.getAnnotatedType();
112        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "non-generic");
113        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
114                + inner.getAnnotations().length);
115
116        // make sure owner is correctly annotated, on the correct type
117        AnnotatedType outer = inner.getAnnotatedOwnerType();
118        Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
119        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
120        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
121                + outer.getAnnotations().length);
122    }
123
124    public static void testInnerGeneric() throws Exception {
125        Field f = GetAnnotatedOwnerType.class.getField("innerGeneric");
126
127        // make sure inner is correctly annotated
128        AnnotatedType inner = f.getAnnotatedType();
129        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
130        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
131                + inner.getAnnotations().length);
132
133        // make sure owner is correctly annotated, on the correct type
134        AnnotatedType outer = inner.getAnnotatedOwnerType();
135        Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
136        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
137        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
138                + outer.getAnnotations().length);
139    }
140
141    public static void testInnerRaw() throws Exception {
142        Field f = GetAnnotatedOwnerType.class.getField("innerRaw");
143
144        // make sure inner is correctly annotated
145        AnnotatedType inner = f.getAnnotatedType();
146        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
147        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
148                + inner.getAnnotations().length);
149
150        // make sure owner is correctly annotated, on the correct type
151        AnnotatedType outer = inner.getAnnotatedOwnerType();
152        Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
153        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
154        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
155                + outer.getAnnotations().length);
156    }
157
158    public static void testLocalClass() throws Exception {
159        class ALocalClass {}
160        class OneMore {
161            public @TA("null") ALocalClass c;
162        }
163        testNegative(OneMore.class.getField("c").getAnnotatedType(), "Local class should return null");
164    }
165
166    public static void testAnonymousClass() throws Exception {
167        testNegative(GetAnnotatedOwnerType.class.getField("anonymous").getAnnotatedType(),
168                "Anonymous class should return null");
169    }
170
171    public static void testArray() throws Exception {
172        AnnotatedType t = GetAnnotatedOwnerType.class.getField("dummy").getAnnotatedType();
173        Asserts.assertTrue((t instanceof AnnotatedArrayType),
174                "Was expecting an AnnotatedArrayType " + t);
175        testNegative(t, "" + t + " should not have an annotated owner type");
176    }
177
178    public static void testWildcard() throws Exception {
179        AnnotatedType tt = GetAnnotatedOwnerType.class.getField("wildcard").getAnnotatedType();
180        AnnotatedType t = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
181        Asserts.assertTrue((t instanceof AnnotatedWildcardType),
182                "Was expecting an AnnotatedWildcardType " + t);
183        testNegative(t, "" + t + " should not have an annotated owner type");
184    }
185
186    public static void testTypeParameter() throws Exception {
187        AnnotatedType t = GetAnnotatedOwnerType.class.getField("tv").getAnnotatedType();
188        Asserts.assertTrue((t instanceof AnnotatedTypeVariable),
189                "Was expecting an AnnotatedTypeVariable " + t);
190        testNegative(t, "" + t + " should not have an annotated owner type");
191    }
192
193    public static void testTypeArgument() throws Exception {
194        AnnotatedType tt = GetAnnotatedOwnerType.class.getField("typeArgument").getAnnotatedType();
195        Asserts.assertEquals(tt.getAnnotation(TA.class).value(), "bad");
196        Asserts.assertTrue(tt.getAnnotations().length == 1, "expecting one (1) annotation, got: "
197                + tt.getAnnotations().length);
198
199        // make sure inner is correctly annotated
200        AnnotatedType inner = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
201        Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "tb");
202        Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
203                + inner.getAnnotations().length);
204
205        // make sure owner is correctly annotated
206        AnnotatedType outer = inner.getAnnotatedOwnerType();
207        Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "good");
208        Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
209                + outer.getAnnotations().length);
210    }
211
212    public static void testComplicated() throws Exception {
213        Field f = GetAnnotatedOwnerType.class.getField("complicated");
214
215        // Outermost level
216        AnnotatedType t = f.getAnnotatedType();
217        Asserts.assertTrue((t instanceof AnnotatedArrayType),
218                "Was expecting an AnnotatedArrayType " + t);
219        testNegative(t, "" + t + " should not have an annotated owner type");
220        Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
221                + t.getAnnotations().length);
222
223        // Component type
224        t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
225        testNegative(t, "" + t + " should not have an annotated owner type");
226        Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
227                + t.getAnnotations().length);
228
229        // Type arg GetAnnotatedOwnerType<String>...D<Number>
230        t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[0];
231        Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
232                + t.getAnnotations().length);
233
234        // C<Class<?>, ? extends ...>
235        t = t.getAnnotatedOwnerType();
236        Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
237                + t.getAnnotations().length);
238
239        // ? extends
240        t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[1];
241        testNegative(t, "" + t + " should not have an annotated owner type");
242        Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
243                + t.getAnnotations().length);
244
245        // @TA("complicated") Exception
246        t = ((AnnotatedWildcardType)t).getAnnotatedUpperBounds()[0];
247        testNegative(t, "" + t + " should not have an annotated owner type");
248        Asserts.assertEquals(t.getAnnotation(TA.class).value(), "complicated");
249        Asserts.assertTrue(t.getAnnotations().length == 1, "expecting one (1) annotation, got: "
250                + t.getAnnotations().length);
251    }
252
253    private static void testNegative(AnnotatedType t, String msg) {
254        Asserts.assertNull(t.getAnnotatedOwnerType(), msg);
255    }
256
257    public class Nested<AlsoDummy> {}
258    public class B {
259        public class C<R, S> {
260            public class D<T> {
261            }
262        }
263    }
264
265    @Target(ElementType.TYPE_USE)
266    @Retention(RetentionPolicy.RUNTIME)
267    public @interface TA {
268        String value();
269    }
270
271    @Target(ElementType.TYPE_USE)
272    @Retention(RetentionPolicy.RUNTIME)
273    public @interface TB {
274        String value();
275    }
276}
277
278class GetAnnotatedOwnerTypeAuxilliary {
279    class Inner {}
280
281    class InnerGeneric<Dummy> {}
282}
283