1 /*
2  * Copyright (c) 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.
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 8046171
27  * @summary Test access to private methods between nestmates and nest-host
28  *          using different flavours of named nested types using MethodHandles
29  * @run main TestMethodHandles
30  */
31 
32 
33 import java.lang.invoke.*;
34 import static java.lang.invoke.MethodHandles.*;
35 import static java.lang.invoke.MethodType.*;
36 
37 public class TestMethodHandles {
38 
39     static final MethodType M_T = MethodType.methodType(void.class);
40 
41     // Private method of nest-host for nestmates to access
priv_invoke()42     private void priv_invoke() {
43         System.out.println("TestMethodHandles::priv_invoke");
44     }
45 
46     // public constructor so we aren't relying on private access
TestMethodHandles()47     public TestMethodHandles() {}
48 
49     // Methods that will access private methods of nestmates
50 
access_priv(TestMethodHandles o)51     void access_priv(TestMethodHandles o) throws Throwable {
52         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
53         mh.invoke(o);
54         mh.invokeExact(o);
55         checkBadInvoke(mh, new StaticNested()); // wrong nestmate
56         checkBadInvoke(mh, mh); // completely wrong type
57         // findSpecial also works when this and o are the same class
58         mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
59         mh.invoke(o);
60         mh.invokeExact(o);
61         checkBadInvoke(mh, new StaticNested()); // wrong nestmate
62         checkBadInvoke(mh, mh); // completely wrong type
63     }
access_priv(InnerNested o)64     void access_priv(InnerNested o) throws Throwable {
65         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
66         mh.invoke(o);
67         mh.invokeExact(o);
68         checkBadInvoke(mh, this); // wrong nestmate
69         checkBadInvoke(mh, mh); // completely wrong type
70         try {
71             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
72             throw new Error("findSpecial() succeeded unexpectedly");
73         }
74         catch (IllegalAccessException expected) {}
75     }
access_priv(StaticNested o)76     void access_priv(StaticNested o) throws Throwable {
77         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
78         mh.invoke(o);
79         mh.invokeExact(o);
80         checkBadInvoke(mh, this); // wrong nestmate
81         checkBadInvoke(mh, mh); // completely wrong type
82         try {
83             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
84             throw new Error("findSpecial() succeeded unexpectedly");
85         }
86         catch (IllegalAccessException expected) {}
87     }
access_priv(StaticIface o)88     void access_priv(StaticIface o) throws Throwable {
89         MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
90         mh.invoke(o);
91         mh.invokeExact(o);
92         checkBadInvoke(mh, this); // wrong nestmate
93         checkBadInvoke(mh, mh); // completely wrong type
94         try {
95             mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
96             throw new Error("findSpecial() succeeded unexpectedly");
97         }
98         catch (IllegalAccessException expected) {}
99     }
100 
101     // The various nestmates
102 
103     static interface StaticIface {
104 
priv_invoke()105         private void priv_invoke() {
106             System.out.println("StaticIface::priv_invoke");
107         }
108 
109         // Methods that will access private methods of nestmates
110 
access_priv(TestMethodHandles o)111         default void access_priv(TestMethodHandles o) throws Throwable {
112             MethodHandle mh =
113               lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
114             mh.invoke(o);
115             mh.invokeExact(o);
116             checkBadInvoke(mh, this); // wrong nestmate
117             checkBadInvoke(mh, mh); // completely wrong type
118             try {
119                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
120                 throw new Error("findSpecial() succeeded unexpectedly");
121             }
122             catch (IllegalAccessException expected) {}
123         }
access_priv(InnerNested o)124         default void access_priv(InnerNested o) throws Throwable {
125             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
126             mh.invoke(o);
127             mh.invokeExact(o);
128             checkBadInvoke(mh, this); // wrong nestmate
129             checkBadInvoke(mh, mh); // completely wrong type
130             try {
131                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
132                 throw new Error("findSpecial() succeeded unexpectedly");
133             }
134             catch (IllegalAccessException expected) {}
135         }
access_priv(StaticNested o)136         default void access_priv(StaticNested o) throws Throwable {
137             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
138             mh.invoke(o);
139             mh.invokeExact(o);
140             checkBadInvoke(mh, this); // wrong nestmate
141             checkBadInvoke(mh, mh); // completely wrong type
142             try {
143                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
144                 throw new Error("findSpecial() succeeded unexpectedly");
145             }
146             catch (IllegalAccessException expected) {}
147         }
access_priv(StaticIface o)148         default void access_priv(StaticIface o) throws Throwable {
149             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
150             mh.invoke(o);
151             mh.invokeExact(o);
152             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
153             checkBadInvoke(mh, mh); // completely wrong type
154             // findSpecial also works when this and o are the same interface
155             mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, StaticIface.class);
156             mh.invoke(o);
157             mh.invokeExact(o);
158             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
159             checkBadInvoke(mh, mh); // completely wrong type
160         }
161     }
162 
163     static class StaticNested {
164 
priv_invoke()165         private void priv_invoke() {
166             System.out.println("StaticNested::priv_invoke");
167         }
168 
169         // public constructor so we aren't relying on private access
StaticNested()170         public StaticNested() {}
171 
172         // Methods that will access private methods of nestmates
173 
access_priv(TestMethodHandles o)174         void access_priv(TestMethodHandles o) throws Throwable {
175             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
176             mh.invoke(o);
177             mh.invokeExact(o);
178             checkBadInvoke(mh, this); // wrong nestmate
179             checkBadInvoke(mh, mh); // completely wrong type
180             try {
181                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
182                 throw new Error("findSpecial() succeeded unexpectedly");
183             }
184             catch (IllegalAccessException expected) {}
185         }
access_priv(InnerNested o)186         void access_priv(InnerNested o) throws Throwable {
187             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
188             mh.invoke(o);
189             mh.invokeExact(o);
190             checkBadInvoke(mh, this); // wrong nestmate
191             checkBadInvoke(mh, mh); // completely wrong type
192             try {
193                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
194                 throw new Error("findSpecial() succeeded unexpectedly");
195             }
196             catch (IllegalAccessException expected) {}
197         }
access_priv(StaticNested o)198         void access_priv(StaticNested o) throws Throwable {
199             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
200             mh.invoke(o);
201             mh.invokeExact(o);
202             checkBadInvoke(mh, new TestMethodHandles()); // wrong nestmate
203             checkBadInvoke(mh, mh); // completely wrong type
204             // findSpecial also works when this and o are the same class
205             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
206             mh.invoke(o);
207             mh.invokeExact(o);
208             checkBadInvoke(mh, new TestMethodHandles()); // wrong nestmate
209             checkBadInvoke(mh, mh); // completely wrong type
210         }
access_priv(StaticIface o)211         void access_priv(StaticIface o) throws Throwable {
212             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
213             mh.invoke(o);
214             mh.invokeExact(o);
215             checkBadInvoke(mh, this); // wrong nestmate
216             checkBadInvoke(mh, mh); // completely wrong type
217             try {
218                 mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
219                 throw new Error("findSpecial() succeeded unexpectedly");
220             }
221             catch (IllegalAccessException expected) {}
222         }
223     }
224 
225     class InnerNested {
226 
priv_invoke()227         private void priv_invoke() {
228             System.out.println("InnerNested::priv_invoke");
229         }
230 
231         // public constructor so we aren't relying on private access
InnerNested()232         public InnerNested() {}
233 
access_priv(TestMethodHandles o)234         void access_priv(TestMethodHandles o) throws Throwable {
235             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
236             mh.invoke(o);
237             mh.invokeExact(o);
238             checkBadInvoke(mh, this); // wrong nestmate
239             checkBadInvoke(mh, mh); // completely wrong type
240             try {
241                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
242                 throw new Error("findSpecial() succeeded unexpectedly");
243             }
244             catch (IllegalAccessException expected) {}
245         }
access_priv(InnerNested o)246         void access_priv(InnerNested o) throws Throwable {
247             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
248             mh.invoke(o);
249             mh.invokeExact(o);
250             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
251             checkBadInvoke(mh, mh); // completely wrong type
252             // findSpecial also works when this and o are the same class
253             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
254             mh.invoke(o);
255             mh.invokeExact(o);
256             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
257             checkBadInvoke(mh, mh); // completely wrong type
258         }
access_priv(StaticNested o)259         void access_priv(StaticNested o) throws Throwable {
260             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
261             mh.invoke(o);
262             mh.invokeExact(o);
263             checkBadInvoke(mh, this); // wrong nestmate
264             checkBadInvoke(mh, mh); // completely wrong type
265             try {
266                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
267                 throw new Error("findSpecial() succeeded unexpectedly");
268             }
269             catch (IllegalAccessException expected) {}
270         }
access_priv(StaticIface o)271         void access_priv(StaticIface o) throws Throwable {
272             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
273             mh.invoke(o);
274             mh.invokeExact(o);
275             checkBadInvoke(mh, this); // wrong nestmate
276             checkBadInvoke(mh, mh); // completely wrong type
277             try {
278                 mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
279                 throw new Error("findSpecial() succeeded unexpectedly");
280             }
281             catch (IllegalAccessException expected) {}
282         }
283     }
284 
checkBadInvoke(MethodHandle mh, Object o)285     static void checkBadInvoke(MethodHandle mh, Object o) throws Throwable {
286         try {
287             mh.invoke(o);
288             throw new Error("Invoke on MethodHandle " + mh + " with receiver "
289                             + o + "should have failed with ClassCastException!");
290          }
291          catch (ClassCastException expected) {
292              System.out.println("invoke got expected exception: " + expected);
293          }
294     }
295 
main(String[] args)296     public static void main(String[] args) throws Throwable {
297         TestMethodHandles o = new TestMethodHandles();
298         StaticNested s = new StaticNested();
299         InnerNested i = o.new InnerNested();
300         StaticIface intf = new StaticIface() {};
301 
302         o.access_priv(new TestMethodHandles());
303         o.access_priv(i);
304         o.access_priv(s);
305         o.access_priv(intf);
306 
307         s.access_priv(o);
308         s.access_priv(i);
309         s.access_priv(new StaticNested());
310         s.access_priv(intf);
311 
312         i.access_priv(o);
313         i.access_priv(o.new InnerNested());
314         i.access_priv(s);
315         i.access_priv(intf);
316 
317         intf.access_priv(o);
318         intf.access_priv(i);
319         intf.access_priv(s);
320         intf.access_priv(new StaticIface(){});
321     }
322 }
323