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 8054987
27  * @summary Test sharing of annotations between Executable/Field instances.
28  *          Sharing should not be noticeable when performing mutating
29  *          operations.
30  * @run testng AnnotationSharing
31  */
32 
33 import java.lang.annotation.*;
34 import java.lang.reflect.*;
35 
36 import org.testng.annotations.Test;
37 
38 public class AnnotationSharing {
39     @Test
testMethodSharing()40     public void testMethodSharing() throws Exception {
41         Method[] m1 = AnnotationSharing.class.getMethods();
42         Method[] m2 = AnnotationSharing.class.getMethods();
43         validateSharingSafelyObservable(m1, m2);
44     }
45 
46     @Test
testDeclaredMethodSharing()47     public void testDeclaredMethodSharing() throws Exception {
48         Method[] m3 = AnnotationSharing.class.getDeclaredMethods();
49         Method[] m4 = AnnotationSharing.class.getDeclaredMethods();
50         validateSharingSafelyObservable(m3, m4);
51     }
52 
53     @Test
testFieldSharing()54     public void testFieldSharing() throws Exception {
55         Field[] f1 = AnnotationSharing.class.getFields();
56         Field[] f2 = AnnotationSharing.class.getFields();
57         validateSharingSafelyObservable(f1, f2);
58     }
59 
60     @Test
testDeclaredFieldsSharing()61     public void testDeclaredFieldsSharing() throws Exception {
62         Field[] f3 = AnnotationSharing.class.getDeclaredFields();
63         Field[] f4 = AnnotationSharing.class.getDeclaredFields();
64         validateSharingSafelyObservable(f3, f4);
65     }
66 
67     @Test
testMethodSharingOccurs()68     public void testMethodSharingOccurs() throws Exception {
69         Method mm1 = AnnotationSharing.class.getDeclaredMethod("m", (Class<?>[])null);
70         Method mm2 = AnnotationSharing.class.getDeclaredMethod("m", (Class<?>[])null);
71         validateAnnotationSharing(mm1, mm2);
72     }
73 
74     @Test
testMethodSharingIsSafe()75     public void testMethodSharingIsSafe() throws Exception {
76         Method mm1 = AnnotationSharing.class.getDeclaredMethod("m", (Class<?>[])null);
77         Method mm2 = AnnotationSharing.class.getDeclaredMethod("m", (Class<?>[])null);
78         validateAnnotationSharingIsSafe(mm1, mm2);
79         validateArrayValues(mm1.getAnnotation(Baz.class), mm2.getAnnotation(Baz.class));
80     }
81 
82     @Test
testFieldSharingOccurs()83     public void testFieldSharingOccurs() throws Exception {
84         Field ff1 = AnnotationSharing.class.getDeclaredField("f");
85         Field ff2 = AnnotationSharing.class.getDeclaredField("f");
86         validateAnnotationSharing(ff1, ff2);
87     }
88 
89     @Test
testFieldSharingIsSafe()90     public void testFieldSharingIsSafe() throws Exception {
91         Field ff1 = AnnotationSharing.class.getDeclaredField("f");
92         Field ff2 = AnnotationSharing.class.getDeclaredField("f");
93         validateAnnotationSharingIsSafe(ff1, ff2);
94         validateArrayValues(ff1.getAnnotation(Baz.class), ff2.getAnnotation(Baz.class));
95     }
96 
97     // Validate that AccessibleObject instances are not shared
validateSharingSafelyObservable(AccessibleObject[] m1, AccessibleObject[] m2)98     private static void validateSharingSafelyObservable(AccessibleObject[] m1, AccessibleObject[] m2)
99             throws Exception {
100 
101         // Validate that setAccessible works
102         for (AccessibleObject m : m1)
103             m.setAccessible(false);
104 
105         for (AccessibleObject m : m2)
106             m.setAccessible(true);
107 
108         for (AccessibleObject m : m1)
109             if (m.isAccessible())
110                 throw new RuntimeException(m + " should not be accessible");
111 
112         for (AccessibleObject m : m2)
113             if (!m.isAccessible())
114                 throw new RuntimeException(m + " should be accessible");
115 
116         // Validate that methods are still equal()
117         for (int i = 0; i < m1.length; i++)
118             if (!m1[i].equals(m2[i]))
119                 throw new RuntimeException(m1[i] + " and " + m2[i] + " should be equal()");
120 
121         // Validate that the arrays aren't shared
122         for (int i = 0; i < m1.length; i++)
123             m1[i] = null;
124 
125         for (int i = 0; i < m2.length; i++)
126             if (m2[i] == null)
127                 throw new RuntimeException("Detected sharing of AccessibleObject arrays");
128     }
129 
130     // Validate that annotations are shared
validateAnnotationSharing(AccessibleObject m1, AccessibleObject m2)131     private static void validateAnnotationSharing(AccessibleObject m1, AccessibleObject m2) {
132         Bar b1 = m1.getAnnotation(Bar.class);
133         Bar b2 = m2.getAnnotation(Bar.class);
134 
135         if (b1 != b2)
136             throw new RuntimeException(b1 + " and " + b2 + " should be ==");
137 
138     }
139 
140     // Validate that Method instances representing the annotation elements
141     // behave as intended
validateAnnotationSharingIsSafe(AccessibleObject m1, AccessibleObject m2)142     private static void validateAnnotationSharingIsSafe(AccessibleObject m1, AccessibleObject m2)
143             throws Exception {
144         Bar b1 = m1.getAnnotation(Bar.class);
145         Bar b2 = m2.getAnnotation(Bar.class);
146 
147         Method mm1 = b1.annotationType().getMethod("value", (Class<?>[]) null);
148         Method mm2 = b2.annotationType().getMethod("value", (Class<?>[]) null);
149         inner(mm1, mm2);
150 
151         mm1 = b1.getClass().getMethod("value", (Class<?>[]) null);
152         mm2 = b2.getClass().getMethod("value", (Class<?>[]) null);
153         inner(mm1, mm2);
154 
155     }
inner(Method mm1, Method mm2)156     private static void inner(Method mm1, Method mm2)
157             throws Exception {
158         if (!mm1.equals(mm2))
159             throw new RuntimeException(mm1 + " and " + mm2 + " should be equal()");
160 
161         mm1.setAccessible(false);
162         mm2.setAccessible(true);
163 
164         if (mm1.isAccessible())
165             throw new RuntimeException(mm1 + " should not be accessible");
166 
167         if (!mm2.isAccessible())
168             throw new RuntimeException(mm2 + " should be accessible");
169     }
170 
171     // Validate that array element values are not shared
validateArrayValues(Baz a, Baz b)172     private static void validateArrayValues(Baz a, Baz b) {
173         String[] s1 = a.value();
174         String[] s2 = b.value();
175 
176         s1[0] = "22";
177 
178         if (!s2[0].equals("1"))
179             throw new RuntimeException("Mutation of array elements should not be detectable");
180     }
181 
182     @Foo @Bar("val") @Baz({"1", "2"})
m()183     public void m() {
184         return ;
185     }
186 
187     @Foo @Bar("someValue") @Baz({"1", "22", "33"})
188     public Object f = new Object();
189 }
190 
191 @Retention(RetentionPolicy.RUNTIME)
192 @interface Foo {}
193 
194 @Retention(RetentionPolicy.RUNTIME)
195 @interface Bar {
value()196     String value();
197 }
198 
199 @Retention(RetentionPolicy.RUNTIME)
200 @interface Baz {
value()201     String [] value();
202 }
203