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 
30 import org.testng.Assert;
31 import org.testng.annotations.Test;
32 
33 import java.lang.annotation.Annotation;
34 import java.lang.annotation.AnnotationFormatError;
35 import java.util.Arrays;
36 import java.util.Set;
37 import java.util.stream.Collectors;
38 import 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 
55 public class AnnotationVerifier {
56 
57     //=======================================================
58     // GoodAnnotation...
59 
60     @GoodAnnotation
61     static class HolderA {
62     }
63 
64     @Test
holderA_goodAnnotation()65     public void holderA_goodAnnotation() {
66         testGetAnnotation(HolderA.class, GoodAnnotation.class, true);
67     }
68 
69     @Test
holderA_annotations()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
holderB_annotationWithParameter()90     public void holderB_annotationWithParameter() {
91         testGetAnnotation(HolderB.class, AnnotationWithParameter.class, false);
92     }
93 
94     @Test
holderB_goodAnnotation()95     public void holderB_goodAnnotation() {
96         testGetAnnotation(HolderB.class, GoodAnnotation.class, true);
97     }
98 
99     @Test
holderB_annotations()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)
holderC_annotationWithVoidReturn()120     public void holderC_annotationWithVoidReturn() {
121         testGetAnnotation(HolderC.class, AnnotationWithVoidReturn.class, false);
122     }
123 
124     @Test(expectedExceptions = AnnotationFormatError.class)
holderC_goodAnnotation()125     public void holderC_goodAnnotation() {
126         testGetAnnotation(HolderC.class, GoodAnnotation.class, false);
127     }
128 
129     @Test(expectedExceptions = AnnotationFormatError.class)
holderC_annotations()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)
holderD_annotationWithExtraInterface()150     public void holderD_annotationWithExtraInterface() {
151         testGetAnnotation(HolderD.class, AnnotationWithExtraInterface.class, false);
152     }
153 
154     @Test(expectedExceptions = AnnotationFormatError.class)
holderD_goodAnnotation()155     public void holderD_goodAnnotation() {
156         testGetAnnotation(HolderD.class, GoodAnnotation.class, false);
157     }
158 
159     @Test(expectedExceptions = AnnotationFormatError.class)
holderD_annotations()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
holderE_annotationWithException()184     public void holderE_annotationWithException() {
185         testGetAnnotation(HolderE.class, AnnotationWithException.class, true);
186     }
187 
188     @Test
holderE_goodAnnotation()189     public void holderE_goodAnnotation() {
190         testGetAnnotation(HolderE.class, GoodAnnotation.class, true);
191     }
192 
193     @Test
holderE_annotations()194     public void holderE_annotations() {
195         testGetAnnotations(HolderE.class, GoodAnnotation.class, AnnotationWithException.class);
196     }
197 
198     @Test(expectedExceptions = AnnotationFormatError.class)
holderE_annotationWithException_equals()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
holderF_annotationWithHashCode()233     public void holderF_annotationWithHashCode() {
234         testGetAnnotation(HolderF.class, AnnotationWithHashCode.class, true);
235     }
236 
237     @Test
holderF_goodAnnotation()238     public void holderF_goodAnnotation() {
239         testGetAnnotation(HolderF.class, GoodAnnotation.class, true);
240     }
241 
242     @Test
holderF_annotations()243     public void holderF_annotations() {
244         testGetAnnotations(HolderF.class, GoodAnnotation.class, AnnotationWithHashCode.class);
245     }
246 
247     @Test(expectedExceptions = AnnotationFormatError.class)
holderF_annotationWithHashCode_equals()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
holderG_annotationWithDefaultMember()283     public void holderG_annotationWithDefaultMember() {
284         testGetAnnotation(HolderG.class, AnnotationWithDefaultMember.class, true);
285     }
286 
287     @Test
holderG_goodAnnotation()288     public void holderG_goodAnnotation() {
289         testGetAnnotation(HolderG.class, GoodAnnotation.class, true);
290     }
291 
292     @Test
holderG_annotations()293     public void holderG_annotations() {
294         testGetAnnotations(HolderG.class, GoodAnnotation.class, AnnotationWithDefaultMember.class);
295     }
296 
297     @Test(expectedExceptions = AnnotationFormatError.class)
holderG_annotationWithDefaultMember_equals()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
holderX_annotationWithoutAnnotationAccessModifier()330     public void holderX_annotationWithoutAnnotationAccessModifier() {
331         testGetAnnotation(HolderX.class, AnnotationWithoutAnnotationAccessModifier.class, false);
332     }
333 
334     @Test
holderX_goodAnnotation()335     public void holderX_goodAnnotation() {
336         testGetAnnotation(HolderX.class, GoodAnnotation.class, true);
337     }
338 
339     @Test
holderX_annotations()340     public void holderX_annotations() {
341         testGetAnnotations(HolderX.class, GoodAnnotation.class);
342     }
343 
344     //=======================================================
345     // utils
346     //
347 
testGetAnnotation(Class<?> holderClass, Class<? extends Annotation> annType, boolean expectedPresent)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 
testGetAnnotations(Class<?> holderClass, Class<? extends Annotation> ... expectedTypes)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 
testEquals(Annotation ann1, Annotation ann2, boolean expectedEquals)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