20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* @test |
24 /* @test |
25 * @bug 8152645 |
25 * @bug 8152645 8216558 |
26 * @summary test field lookup accessibility of MethodHandles and VarHandles |
26 * @summary test field lookup accessibility of MethodHandles and VarHandles |
27 * @compile TestFieldLookupAccessibility.java |
27 * @compile TestFieldLookupAccessibility.java |
28 * pkg/A.java pkg/B_extends_A.java pkg/C.java |
28 * pkg/A.java pkg/B_extends_A.java pkg/C.java |
29 * pkg/subpkg/B_extends_A.java pkg/subpkg/C.java |
29 * pkg/subpkg/B_extends_A.java pkg/subpkg/C.java |
30 * @run testng/othervm TestFieldLookupAccessibility |
30 * @run testng/othervm TestFieldLookupAccessibility |
94 }, |
94 }, |
95 MH_UNREFLECT_GETTER_ACCESSIBLE() { |
95 MH_UNREFLECT_GETTER_ACCESSIBLE() { |
96 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
96 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
97 return l.unreflectGetter(cloneAndSetAccessible(f)); |
97 return l.unreflectGetter(cloneAndSetAccessible(f)); |
98 } |
98 } |
|
99 |
|
100 // Setting the accessibility bit of a Field grants access under |
|
101 // all conditions for MethodHandle getters. |
|
102 Set<String> inaccessibleFields(Set<String> inaccessibleFields) { |
|
103 return new HashSet<>(); |
|
104 } |
99 }, |
105 }, |
100 MH_UNREFLECT_SETTER() { |
106 MH_UNREFLECT_SETTER() { |
101 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
107 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
102 return l.unreflectSetter(f); |
108 return l.unreflectSetter(f); |
103 } |
109 } |
104 |
110 |
105 boolean isAccessible(Field f) { |
111 boolean isAccessible(Field f) { |
106 return f.isAccessible() || !Modifier.isFinal(f.getModifiers()); |
112 return f.isAccessible() && !Modifier.isStatic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers()); |
107 } |
113 } |
108 }, |
114 }, |
109 MH_UNREFLECT_SETTER_ACCESSIBLE() { |
115 MH_UNREFLECT_SETTER_ACCESSIBLE() { |
110 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
116 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
111 return l.unreflectSetter(cloneAndSetAccessible(f)); |
117 return l.unreflectSetter(cloneAndSetAccessible(f)); |
|
118 } |
|
119 |
|
120 boolean isAccessible(Field f) { |
|
121 return !(Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers())); |
|
122 } |
|
123 |
|
124 // Setting the accessibility bit of a Field grants access to non-static |
|
125 // final fields for MethodHandle setters. |
|
126 Set<String> inaccessibleFields(Set<String>inaccessibleFields) { |
|
127 Set<String> result = new HashSet<>(); |
|
128 inaccessibleFields.stream() |
|
129 .filter(f -> (f.contains("static") && f.contains("final"))) |
|
130 .forEach(result::add); |
|
131 return result; |
112 } |
132 } |
113 }, |
133 }, |
114 VH() { |
134 VH() { |
115 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
135 Object lookup(MethodHandles.Lookup l, Field f) throws Exception { |
116 return l.findVarHandle(f.getDeclaringClass(), f.getName(), f.getType()); |
136 return l.findVarHandle(f.getDeclaringClass(), f.getName(), f.getType()); |
138 // Look up a handle to a field |
158 // Look up a handle to a field |
139 abstract Object lookup(MethodHandles.Lookup l, Field f) throws Exception; |
159 abstract Object lookup(MethodHandles.Lookup l, Field f) throws Exception; |
140 |
160 |
141 boolean isAccessible(Field f) { |
161 boolean isAccessible(Field f) { |
142 return true; |
162 return true; |
|
163 } |
|
164 |
|
165 Set<String> inaccessibleFields(Set<String> inaccessibleFields) { |
|
166 return new HashSet<>(inaccessibleFields); |
143 } |
167 } |
144 |
168 |
145 static Field cloneAndSetAccessible(Field f) throws Exception { |
169 static Field cloneAndSetAccessible(Field f) throws Exception { |
146 // Clone to avoid mutating source field |
170 // Clone to avoid mutating source field |
147 f = f.getDeclaringClass().getDeclaredField(f.getName()); |
171 f = f.getDeclaringClass().getDeclaredField(f.getName()); |
178 } |
202 } |
179 |
203 |
180 @Test(dataProvider = "lookupProvider") |
204 @Test(dataProvider = "lookupProvider") |
181 public void test(FieldLookup fl, Class<?> src, MethodHandles.Lookup l, Set<String> inaccessibleFields) { |
205 public void test(FieldLookup fl, Class<?> src, MethodHandles.Lookup l, Set<String> inaccessibleFields) { |
182 // Add to the expected failures all inaccessible fields due to accessibility modifiers |
206 // Add to the expected failures all inaccessible fields due to accessibility modifiers |
183 Set<String> expected = new HashSet<>(inaccessibleFields); |
207 Set<String> expected = fl.inaccessibleFields(inaccessibleFields); |
184 Map<Field, Throwable> actual = new HashMap<>(); |
208 Map<Field, Throwable> actual = new HashMap<>(); |
185 |
209 |
186 for (Field f : fields(src)) { |
210 for (Field f : fields(src)) { |
187 // Add to the expected failures all inaccessible fields due to static/final modifiers |
211 // Add to the expected failures all inaccessible fields due to static/final modifiers |
188 if (!fl.isAccessible(f)) { |
212 if (!fl.isAccessible(f)) { |
200 |
224 |
201 Set<String> actualFieldNames = actual.keySet().stream().map(Field::getName). |
225 Set<String> actualFieldNames = actual.keySet().stream().map(Field::getName). |
202 collect(Collectors.toSet()); |
226 collect(Collectors.toSet()); |
203 if (!actualFieldNames.equals(expected)) { |
227 if (!actualFieldNames.equals(expected)) { |
204 if (actualFieldNames.isEmpty()) { |
228 if (actualFieldNames.isEmpty()) { |
205 // Setting the accessibility bit of a Field grants access under |
229 Assert.assertEquals(actualFieldNames, expected, "No accessibility failures:"); |
206 // all conditions for MethodHander getters and setters |
|
207 if (fl != FieldLookup.MH_UNREFLECT_GETTER_ACCESSIBLE && |
|
208 fl != FieldLookup.MH_UNREFLECT_SETTER_ACCESSIBLE) { |
|
209 Assert.assertEquals(actualFieldNames, expected, "No accessibility failures:"); |
|
210 } |
|
211 } |
230 } |
212 else { |
231 else { |
213 Assert.assertEquals(actualFieldNames, expected, "Accessibility failures differ:"); |
232 Assert.assertEquals(actualFieldNames, expected, "Accessibility failures differ:"); |
214 } |
233 } |
215 } |
234 } |