1/*
2 * Copyright (c) 2016, 2017, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * Create class file using ASM, slightly modified the ASMifier output
28 */
29
30import org.testng.Assert;
31import org.testng.annotations.Test;
32
33import java.lang.annotation.Annotation;
34import java.lang.annotation.AnnotationFormatError;
35import java.util.Arrays;
36import java.util.Set;
37import java.util.stream.Collectors;
38import java.util.stream.Stream;
39
40/*
41 * @test
42 * @bug 8158510
43 * @summary Verify valid annotation
44 * @modules java.base/jdk.internal.org.objectweb.asm
45 * @modules java.base/sun.reflect.annotation
46 * @clean AnnotationWithVoidReturn AnnotationWithParameter
47 *        AnnotationWithExtraInterface AnnotationWithException
48 *        AnnotationWithHashCode AnnotationWithDefaultMember
49 *        AnnotationWithoutAnnotationAccessModifier HolderX
50 * @compile -XDignore.symbol.file ClassFileGenerator.java GoodAnnotation.java
51 * @run main ClassFileGenerator
52 * @run testng AnnotationVerifier
53 */
54
55public class AnnotationVerifier {
56
57    //=======================================================
58    // GoodAnnotation...
59
60    @GoodAnnotation
61    static class HolderA {
62    }
63
64    @Test
65    public void holderA_goodAnnotation() {
66        testGetAnnotation(HolderA.class, GoodAnnotation.class, true);
67    }
68
69    @Test
70    public void holderA_annotations() {
71        testGetAnnotations(HolderA.class, GoodAnnotation.class);
72    }
73
74    //=======================================================
75    // AnnotationWithParameter...
76
77    /*
78    @Retention(RetentionPolicy.RUNTIME)
79    public @interface AnnotationWithParameter {
80        int m(int x) default -1;
81    }
82    */
83
84    @GoodAnnotation
85    @AnnotationWithParameter
86    static class HolderB {
87    }
88
89    @Test
90    public void holderB_annotationWithParameter() {
91        testGetAnnotation(HolderB.class, AnnotationWithParameter.class, false);
92    }
93
94    @Test
95    public void holderB_goodAnnotation() {
96        testGetAnnotation(HolderB.class, GoodAnnotation.class, true);
97    }
98
99    @Test
100    public void holderB_annotations() {
101        testGetAnnotations(HolderB.class, GoodAnnotation.class);
102    }
103
104    //=======================================================
105    // AnnotationWithVoidReturn...
106
107    /*
108    @Retention(RetentionPolicy.RUNTIME)
109    public @interface AnnotationWithVoidReturn {
110        void m() default 1;
111    }
112    */
113
114    @GoodAnnotation
115    @AnnotationWithVoidReturn
116    static class HolderC {
117    }
118
119    @Test(expectedExceptions = AnnotationFormatError.class)
120    public void holderC_annotationWithVoidReturn() {
121        testGetAnnotation(HolderC.class, AnnotationWithVoidReturn.class, false);
122    }
123
124    @Test(expectedExceptions = AnnotationFormatError.class)
125    public void holderC_goodAnnotation() {
126        testGetAnnotation(HolderC.class, GoodAnnotation.class, false);
127    }
128
129    @Test(expectedExceptions = AnnotationFormatError.class)
130    public void holderC_annotations() {
131        testGetAnnotations(HolderC.class);
132    }
133
134    //=======================================================
135    // AnnotationWithExtraInterface...
136
137    /*
138    @Retention(RetentionPolicy.RUNTIME)
139    public @interface AnnotationWithExtraInterface extends java.io.Serializable {
140        int m() default 1;
141    }
142    */
143
144    @GoodAnnotation
145    @AnnotationWithExtraInterface
146    static class HolderD {
147    }
148
149    @Test(expectedExceptions = AnnotationFormatError.class)
150    public void holderD_annotationWithExtraInterface() {
151        testGetAnnotation(HolderD.class, AnnotationWithExtraInterface.class, false);
152    }
153
154    @Test(expectedExceptions = AnnotationFormatError.class)
155    public void holderD_goodAnnotation() {
156        testGetAnnotation(HolderD.class, GoodAnnotation.class, false);
157    }
158
159    @Test(expectedExceptions = AnnotationFormatError.class)
160    public void holderD_annotations() {
161        testGetAnnotations(HolderD.class);
162    }
163
164    //=======================================================
165    // AnnotationWithException...
166
167    /*
168    @Retention(RetentionPolicy.RUNTIME)
169    public @interface AnnotationWithException {
170        int m() throws Exception default 1;
171    }
172    */
173
174    @GoodAnnotation
175    @AnnotationWithException
176    static class HolderE {
177    }
178
179    @AnnotationWithException
180    static class HolderE2 {
181    }
182
183    @Test
184    public void holderE_annotationWithException() {
185        testGetAnnotation(HolderE.class, AnnotationWithException.class, true);
186    }
187
188    @Test
189    public void holderE_goodAnnotation() {
190        testGetAnnotation(HolderE.class, GoodAnnotation.class, true);
191    }
192
193    @Test
194    public void holderE_annotations() {
195        testGetAnnotations(HolderE.class, GoodAnnotation.class, AnnotationWithException.class);
196    }
197
198    @Test(expectedExceptions = AnnotationFormatError.class)
199    public void holderE_annotationWithException_equals() {
200        AnnotationWithException ann1, ann2;
201        try {
202            ann1 = HolderE.class.getAnnotation(AnnotationWithException.class);
203            ann2 = HolderE2.class.getAnnotation(AnnotationWithException.class);
204        } catch (Throwable t) {
205            throw new AssertionError("Unexpected exception", t);
206        }
207        Assert.assertNotNull(ann1);
208        Assert.assertNotNull(ann2);
209
210        testEquals(ann1, ann2, true); // this throws AnnotationFormatError
211    }
212
213    //=======================================================
214    // AnnotationWithHashCode...
215
216    /*
217    @Retention(RetentionPolicy.RUNTIME)
218    public @interface AnnotationWithHashCode {
219        int hashCode() default 1;
220    }
221    */
222
223    @GoodAnnotation
224    @AnnotationWithHashCode
225    static class HolderF {
226    }
227
228    @AnnotationWithHashCode
229    static class HolderF2 {
230    }
231
232    @Test
233    public void holderF_annotationWithHashCode() {
234        testGetAnnotation(HolderF.class, AnnotationWithHashCode.class, true);
235    }
236
237    @Test
238    public void holderF_goodAnnotation() {
239        testGetAnnotation(HolderF.class, GoodAnnotation.class, true);
240    }
241
242    @Test
243    public void holderF_annotations() {
244        testGetAnnotations(HolderF.class, GoodAnnotation.class, AnnotationWithHashCode.class);
245    }
246
247    @Test(expectedExceptions = AnnotationFormatError.class)
248    public void holderF_annotationWithHashCode_equals() {
249        AnnotationWithHashCode ann1, ann2;
250        try {
251            ann1 = HolderF.class.getAnnotation(AnnotationWithHashCode.class);
252            ann2 = HolderF2.class.getAnnotation(AnnotationWithHashCode.class);
253        } catch (Throwable t) {
254            throw new AssertionError("Unexpected exception", t);
255        }
256        Assert.assertNotNull(ann1);
257        Assert.assertNotNull(ann2);
258
259        testEquals(ann1, ann2, true); // this throws AnnotationFormatError
260    }
261
262    //=======================================================
263    // AnnotationWithDefaultMember...
264
265    /*
266    @Retention(RetentionPolicy.RUNTIME)
267    public @interface AnnotationWithDefaultMember {
268        int m() default 1;
269        default int d() default 2 { return 2; }
270    }
271    */
272
273    @GoodAnnotation
274    @AnnotationWithDefaultMember
275    static class HolderG {
276    }
277
278    @AnnotationWithDefaultMember
279    static class HolderG2 {
280    }
281
282    @Test
283    public void holderG_annotationWithDefaultMember() {
284        testGetAnnotation(HolderG.class, AnnotationWithDefaultMember.class, true);
285    }
286
287    @Test
288    public void holderG_goodAnnotation() {
289        testGetAnnotation(HolderG.class, GoodAnnotation.class, true);
290    }
291
292    @Test
293    public void holderG_annotations() {
294        testGetAnnotations(HolderG.class, GoodAnnotation.class, AnnotationWithDefaultMember.class);
295    }
296
297    @Test(expectedExceptions = AnnotationFormatError.class)
298    public void holderG_annotationWithDefaultMember_equals() {
299        AnnotationWithDefaultMember ann1, ann2;
300        try {
301            ann1 = HolderG.class.getAnnotation(AnnotationWithDefaultMember.class);
302            ann2 = HolderG2.class.getAnnotation(AnnotationWithDefaultMember.class);
303        } catch (Throwable t) {
304            throw new AssertionError("Unexpected exception", t);
305        }
306        Assert.assertNotNull(ann1);
307        Assert.assertNotNull(ann2);
308
309        testEquals(ann1, ann2, true); // this throws AnnotationFormatError
310    }
311
312    //=======================================================
313    // AnnotationWithoutAnnotationAccessModifier...
314
315    /*
316
317    @Retention(RetentionPolicy.RUNTIME)
318    public interface AnnotationWithoutAnnotationAccessModifier extends Annotation {
319        int m() default 1;
320    }
321
322    @GoodAnnotation
323    @AnnotationWithoutAnnotationAccessModifier
324    static class HolderX {
325    }
326
327    */
328
329    @Test
330    public void holderX_annotationWithoutAnnotationAccessModifier() {
331        testGetAnnotation(HolderX.class, AnnotationWithoutAnnotationAccessModifier.class, false);
332    }
333
334    @Test
335    public void holderX_goodAnnotation() {
336        testGetAnnotation(HolderX.class, GoodAnnotation.class, true);
337    }
338
339    @Test
340    public void holderX_annotations() {
341        testGetAnnotations(HolderX.class, GoodAnnotation.class);
342    }
343
344    //=======================================================
345    // utils
346    //
347
348    private static void testGetAnnotation(Class<?> holderClass,
349                                          Class<? extends Annotation> annType,
350                                          boolean expectedPresent) {
351        Object result = null;
352        try {
353            try {
354                result = holderClass.getAnnotation(annType);
355                if (expectedPresent != (result != null)) {
356                    throw new AssertionError("Expected " +
357                                             (expectedPresent ? "non-null" : "null") +
358                                             " result, but got: " + result);
359                }
360            } catch (Throwable t) {
361                result = t;
362                throw t;
363            }
364        } finally {
365            System.out.println("\n" +
366                               holderClass.getSimpleName() +
367                               ".class.getAnnotation(" +
368                               annType.getSimpleName() +
369                               ".class) = " +
370                               result);
371        }
372    }
373
374    private static void testGetAnnotations(Class<?> holderClass,
375                                           Class<? extends Annotation> ... expectedTypes) {
376        Object result = null;
377        try {
378            try {
379                Annotation[] anns = holderClass.getAnnotations();
380
381                Set<Class<? extends Annotation>> gotTypes =
382                    Stream.of(anns)
383                          .map(Annotation::annotationType)
384                          .collect(Collectors.toSet());
385
386                Set<Class<? extends Annotation>> expTypes =
387                    Stream.of(expectedTypes)
388                          .collect(Collectors.toSet());
389
390                if (!expTypes.equals(gotTypes)) {
391                    throw new AssertionError("Expected annotation types: " + expTypes +
392                                             " but got: " + Arrays.toString(anns));
393                }
394                result = Arrays.toString(anns);
395            } catch (Throwable t) {
396                result = t;
397                throw t;
398            }
399        } finally {
400            System.out.println("\n" +
401                               holderClass.getSimpleName() +
402                               ".class.getAnnotations() = " +
403                               result);
404        }
405    }
406
407    private static void testEquals(Annotation ann1, Annotation ann2, boolean expectedEquals) {
408        Object result = null;
409        try {
410            try {
411                boolean gotEquals = ann1.equals(ann2);
412                Assert.assertEquals(gotEquals, expectedEquals);
413                result = gotEquals;
414            } catch (Throwable t) {
415                result = t;
416                throw t;
417            }
418        } finally {
419            System.out.println("\n" + ann1 + ".equals(" + ann2 + ") = " + result);
420        }
421    }
422}
423