1 /*
2  * Copyright (c) 2018, 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 JNI access to private methods between nestmates and nest-host
28  *          using different flavours of named nested types
29  * @compile ../NestmatesJNI.java
30  * @run main/othervm/native TestJNI
31  * @run main/othervm/native -Xcheck:jni TestJNI
32  */
33 public class TestJNI {
34 
35     // Unlike reflection, the calling context is not relevant to JNI
36     // calls, but we keep the same structure as the reflection tests.
37 
38     static final String METHOD = "priv_invoke";
39 
40     // Private method of nest-host for nestmates to access
priv_invoke()41     private void priv_invoke() {
42         System.out.println("TestJNI::priv_invoke");
43     }
44 
45     // public constructor so we aren't relying on private access
TestJNI()46     public TestJNI() {}
47 
48     // Methods that will access private methods of nestmates
49 
access_priv(TestJNI o)50     void access_priv(TestJNI o) {
51         doCall(o, o.getClass(), METHOD, true);
52         doCall(o, o.getClass(), METHOD, false);
53     }
access_priv(InnerNested o)54     void access_priv(InnerNested o) {
55         doCall(o, o.getClass(), METHOD, true);
56         doCall(o, o.getClass(), METHOD, false);
57     }
access_priv(StaticNested o)58     void access_priv(StaticNested o) {
59         doCall(o, o.getClass(), METHOD, true);
60         doCall(o, o.getClass(), METHOD, false);
61     }
access_priv(StaticIface o)62     void access_priv(StaticIface o) {
63         // Can't use o.getClass() as the method is not in that class
64         doCall(o, StaticIface.class, METHOD, true);
65         doCall(o, StaticIface.class, METHOD, false);
66     }
67 
68     // The various nestmates
69 
70     static interface StaticIface {
71 
priv_invoke()72         private void priv_invoke() {
73             System.out.println("StaticIface::priv_invoke");
74         }
75 
76         // Methods that will access private methods of nestmates
77 
access_priv(TestJNI o)78         default void access_priv(TestJNI o) {
79             doCall(o, o.getClass(), METHOD, true);
80             doCall(o, o.getClass(), METHOD, false);
81         }
access_priv(InnerNested o)82         default void access_priv(InnerNested o) {
83             doCall(o, o.getClass(), METHOD, true);
84             doCall(o, o.getClass(), METHOD, false);
85         }
access_priv(StaticNested o)86         default void access_priv(StaticNested o) {
87             doCall(o, o.getClass(), METHOD, true);
88             doCall(o, o.getClass(), METHOD, false);
89         }
access_priv(StaticIface o)90         default void access_priv(StaticIface o) {
91             // Can't use o.getClass() as the method is not in that class
92             doCall(o, StaticIface.class, METHOD, true);
93             doCall(o, StaticIface.class, METHOD, false);
94         }
95     }
96 
97     static class StaticNested {
98 
priv_invoke()99         private void priv_invoke() {
100             System.out.println("StaticNested::priv_invoke");
101         }
102 
103         // public constructor so we aren't relying on private access
StaticNested()104         public StaticNested() {}
105 
106         // Methods that will access private methods of nestmates
107 
access_priv(TestJNI o)108         void access_priv(TestJNI o) {
109             doCall(o, o.getClass(), METHOD, true);
110             doCall(o, o.getClass(), METHOD, false);
111         }
access_priv(InnerNested o)112         void access_priv(InnerNested o) {
113             doCall(o, o.getClass(), METHOD, true);
114             doCall(o, o.getClass(), METHOD, false);
115         }
access_priv(StaticNested o)116         void access_priv(StaticNested o) {
117             doCall(o, o.getClass(), METHOD, true);
118             doCall(o, o.getClass(), METHOD, false);
119         }
access_priv(StaticIface o)120         void access_priv(StaticIface o) {
121             // Can't use o.getClass() as the method is not in that class
122             doCall(o, StaticIface.class, METHOD, true);
123             doCall(o, StaticIface.class, METHOD, false);
124         }
125     }
126 
127     class InnerNested {
128 
priv_invoke()129         private void priv_invoke() {
130             System.out.println("InnerNested::priv_invoke");
131         }
132 
133         // public constructor so we aren't relying on private access
InnerNested()134         public InnerNested() {}
135 
access_priv(TestJNI o)136         void access_priv(TestJNI o) {
137             doCall(o, o.getClass(), METHOD, true);
138             doCall(o, o.getClass(), METHOD, false);
139         }
access_priv(InnerNested o)140         void access_priv(InnerNested o) {
141             doCall(o, o.getClass(), METHOD, true);
142             doCall(o, o.getClass(), METHOD, false);
143         }
access_priv(StaticNested o)144         void access_priv(StaticNested o) {
145             doCall(o, o.getClass(), METHOD, true);
146             doCall(o, o.getClass(), METHOD, false);
147         }
access_priv(StaticIface o)148         void access_priv(StaticIface o) {
149             // Can't use o.getClass() as the method is not in that class
150             doCall(o, StaticIface.class, METHOD, true);
151             doCall(o, StaticIface.class, METHOD, false);
152         }
153     }
154 
main(String[] args)155     public static void main(String[] args) {
156         TestJNI o = new TestJNI();
157         StaticNested s = new StaticNested();
158         InnerNested i = o.new InnerNested();
159         StaticIface intf = new StaticIface() {};
160 
161         o.access_priv(new TestJNI());
162         o.access_priv(i);
163         o.access_priv(s);
164         o.access_priv(intf);
165 
166         s.access_priv(o);
167         s.access_priv(i);
168         s.access_priv(new StaticNested());
169         s.access_priv(intf);
170 
171         i.access_priv(o);
172         i.access_priv(o.new InnerNested());
173         i.access_priv(s);
174         i.access_priv(intf);
175 
176         intf.access_priv(o);
177         intf.access_priv(i);
178         intf.access_priv(s);
179         intf.access_priv(new StaticIface(){});
180     }
181 
182 
doCall(Object target, Class<?> klass, String method, boolean virtual)183     static void doCall(Object target, Class<?> klass, String method,
184                        boolean virtual) {
185         String definingClass = klass.getName();
186         String desc = (virtual ? "Virtual" : "Nonvirtual") + " Invocation of " +
187                        definingClass + "." + method + " on instance of class " +
188                        target.getClass().getName();
189         try {
190             NestmatesJNI.callVoidVoid(target, definingClass, method, virtual);
191             System.out.println(desc + " - passed");
192         }
193         catch (Throwable t) {
194             throw new Error(desc + ": Unexpected exception: " + t, t);
195         }
196     }
197 }
198