• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015, 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 8140450 8152893 8189291
27  * @summary Basic test for StackWalker.getCallerClass()
28  * @run main/othervm GetCallerClassTest
29  * @run main/othervm -Djava.security.manager=allow GetCallerClassTest sm
30  */
31 
32 package test.java.lang.StackWalker;
33 
34 import static java.lang.StackWalker.Option.*;
35 import java.lang.invoke.MethodHandle;
36 import java.lang.invoke.MethodHandles;
37 import java.lang.invoke.MethodType;
38 import java.lang.reflect.InvocationTargetException;
39 import java.lang.reflect.Method;
40 import java.security.Permission;
41 import java.security.PermissionCollection;
42 import java.security.Permissions;
43 import java.security.Policy;
44 import java.security.ProtectionDomain;
45 import java.util.Arrays;
46 import java.util.EnumSet;
47 import java.util.List;
48 import org.testng.annotations.Test;
49 
50 public class GetCallerClassTest {
51     static final Policy DEFAULT_POLICY = Policy.getPolicy();
52     private final StackWalker walker;
53     private final boolean expectUOE;
54 
GetCallerClassTest(StackWalker sw, boolean expect)55     public GetCallerClassTest(StackWalker sw, boolean expect) {
56         this.walker = sw;
57         this.expectUOE = expect;
58     }
59 
60     // Android-changed: Add @Test annotation.
61     // public static void main(String... args) throws Exception {
62     @Test
main()63     public static void main() throws Exception {
64         String[] args = new String[0];
65         if (args.length > 0 && args[0].equals("sm")) {
66             PermissionCollection perms = new Permissions();
67             perms.add(new RuntimePermission("getStackWalkerWithClassReference"));
68             Policy.setPolicy(new Policy() {
69                 @Override
70                 public boolean implies(ProtectionDomain domain, Permission p) {
71                     return perms.implies(p) ||
72                         DEFAULT_POLICY.implies(domain, p);
73                 }
74             });
75             System.setSecurityManager(new SecurityManager());
76         }
77         new GetCallerClassTest(StackWalker.getInstance(), true).test();
78         new GetCallerClassTest(StackWalker.getInstance(RETAIN_CLASS_REFERENCE), false).test();
79         new GetCallerClassTest(StackWalker.getInstance(EnumSet.of(RETAIN_CLASS_REFERENCE,
80                                                                   SHOW_HIDDEN_FRAMES)), false).test();
81     }
82 
test()83     public void test() {
84         new TopLevelCaller().run();
85         new LambdaTest().run();
86         new Nested().createNestedCaller().run();
87         new InnerClassCaller().run();
88         new ReflectionTest().run();
89 
90         List<Thread> threads = Arrays.asList(
91                 new Thread(new TopLevelCaller()),
92                 new Thread(new LambdaTest()),
93                 new Thread(new Nested().createNestedCaller()),
94                 new Thread(new InnerClassCaller()),
95                 new Thread(new ReflectionTest())
96         );
97         threads.stream().forEach(Thread::start);
98         threads.stream().forEach(t -> {
99             try {
100                 t.join();
101             } catch (InterruptedException e) {
102                 throw new RuntimeException(e);
103             }
104         });
105     }
106 
staticGetCallerClass(StackWalker stackWalker, Class<?> expected, boolean expectUOE)107     public static void staticGetCallerClass(StackWalker stackWalker,
108                                             Class<?> expected,
109                                             boolean expectUOE) {
110         try {
111             Class<?> c = stackWalker.getCallerClass();
112             assertEquals(c, expected);
113             if (expectUOE) { // Should have thrown
114                 throw new RuntimeException("Didn't get expected exception");
115             }
116         } catch (RuntimeException e) { // also catches UOE
117             if (expectUOE && causeIsUOE(e)) {
118                 return; /* expected */
119             }
120             System.err.println("Unexpected exception:");
121             throw e;
122         }
123     }
124 
reflectiveGetCallerClass(StackWalker stackWalker, Class<?> expected, boolean expectUOE)125     public static void reflectiveGetCallerClass(StackWalker stackWalker,
126                                                 Class<?> expected,
127                                                 boolean expectUOE) {
128         try {
129             Method m = StackWalker.class.getMethod("getCallerClass");
130             Class<?> c = (Class<?>) m.invoke(stackWalker);
131             assertEquals(c, expected);
132             if (expectUOE) { // Should have thrown
133                 throw new RuntimeException("Didn't get expected exception");
134             }
135         } catch (Throwable e) {
136             if (expectUOE && causeIsUOE(e)) {
137                 return; /* expected */
138             }
139             System.err.println("Unexpected exception:");
140             throw new RuntimeException(e);
141         }
142     }
143 
methodHandleGetCallerClass(StackWalker stackWalker, Class<?> expected, boolean expectUOE)144     public static void methodHandleGetCallerClass(StackWalker stackWalker,
145                                                   Class<?> expected,
146                                                   boolean expectUOE) {
147         MethodHandles.Lookup lookup = MethodHandles.lookup();
148         try {
149             MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass",
150                                                  MethodType.methodType(Class.class));
151             Class<?> c = (Class<?>) mh.invokeExact(stackWalker);
152             assertEquals(c, expected);
153             if (expectUOE) { // Should have thrown
154                 throw new RuntimeException("Didn't get expected exception");
155             }
156         } catch (Throwable e) {
157             if (expectUOE && causeIsUOE(e)) {
158                 return; /* expected */
159             }
160             System.err.println("Unexpected exception:");
161             throw new RuntimeException(e);
162         }
163     }
164 
assertEquals(Class<?> c, Class<?> expected)165     public static void assertEquals(Class<?> c, Class<?> expected) {
166         if (expected != c) {
167             throw new RuntimeException("Got " + c + ", but expected " + expected);
168         }
169     }
170 
171     /** Is there an UnsupportedOperationException in there? */
causeIsUOE(Throwable t)172     public static boolean causeIsUOE(Throwable t) {
173         while (t != null) {
174             if (t instanceof UnsupportedOperationException) {
175                 return true;
176             }
177             t = t.getCause();
178         }
179         return false;
180     }
181 
182     class TopLevelCaller implements Runnable {
run()183         public void run() {
184             GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE);
185             GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE);
186             GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE);
187         }
188     }
189 
190     class LambdaTest implements Runnable {
run()191         public void run() {
192             Runnable lambdaRunnable = () -> {
193                 try {
194                     Class<?> c = walker.getCallerClass();
195 
196                     // Android-changed: Android desugar lambdas.
197                     // assertEquals(c, LambdaTest.class);
198                     if (!c.getName().startsWith(LambdaTest.class.getName())) {
199                         throw new RuntimeException("Expect " + c + " to start with "
200                             + LambdaTest.class);
201                     }
202                     if (expectUOE) { // Should have thrown
203                         throw new RuntimeException("Didn't get expected exception");
204                     }
205                 } catch (Throwable e) {
206                     if (expectUOE && causeIsUOE(e)) {
207                         return; /* expected */
208                     }
209                     System.err.println("Unexpected exception:");
210                     throw new RuntimeException(e);
211                 }
212             };
213             lambdaRunnable.run();
214         }
215     }
216 
217     class Nested {
createNestedCaller()218         NestedClassCaller createNestedCaller() { return new NestedClassCaller(); }
219         class NestedClassCaller implements Runnable {
run()220             public void run() {
221                 GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE);
222                 GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE);
223                 GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE);
224             }
225         }
226     }
227 
228     class InnerClassCaller implements Runnable {
run()229         public void run() {
230             new Inner().test();
231         }
232         class Inner {
test()233             void test() {
234                 GetCallerClassTest.staticGetCallerClass(walker, this.getClass(), expectUOE);
235                 GetCallerClassTest.reflectiveGetCallerClass(walker, this.getClass(), expectUOE);
236                 GetCallerClassTest.methodHandleGetCallerClass(walker, this.getClass(), expectUOE);
237             }
238         }
239     }
240 
241     class ReflectionTest implements Runnable {
242         final MethodType methodType =
243             MethodType.methodType(void.class, StackWalker.class, Class.class, boolean.class);
244 
run()245         public void run() {
246             callMethodHandle();
247             callMethodHandleRefl();
248             callMethodInvoke();
249             callMethodInvokeRefl();
250         }
callMethodHandle()251         void callMethodHandle() {
252             MethodHandles.Lookup lookup = MethodHandles.publicLookup();
253             try {
254                 MethodHandle mh = lookup.findStatic(GetCallerClassTest.class,
255                                                     "staticGetCallerClass",
256                                                     methodType);
257                 mh.invokeExact(walker, ReflectionTest.class, expectUOE);
258             } catch (Throwable e) {
259                 throw new RuntimeException(e);
260             }
261         }
callMethodHandleRefl()262         void callMethodHandleRefl() {
263             MethodHandles.Lookup lookup = MethodHandles.publicLookup();
264             try {
265                 MethodHandle mh = lookup.findStatic(GetCallerClassTest.class,
266                                                     "reflectiveGetCallerClass",
267                                                     methodType);
268                 mh.invokeExact(walker, ReflectionTest.class, expectUOE);
269             } catch (Throwable e) {
270                 throw new RuntimeException(e);
271             }
272         }
callMethodInvoke()273         void callMethodInvoke() {
274             try {
275                 Method m = GetCallerClassTest.class.getMethod("staticGetCallerClass",
276                                StackWalker.class, Class.class, boolean.class);
277                 m.invoke(null, walker, ReflectionTest.class, expectUOE);
278             } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
279                 throw new RuntimeException(e);
280             }
281         }
callMethodInvokeRefl()282         void callMethodInvokeRefl() {
283             try {
284                 Method m = GetCallerClassTest.class.getMethod("reflectiveGetCallerClass",
285                                StackWalker.class, Class.class, boolean.class);
286                 m.invoke(null, walker, ReflectionTest.class, expectUOE);
287             } catch (UnsupportedOperationException e) {
288                 throw e;
289             } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
290                 throw new RuntimeException(e);
291             }
292         }
293     }
294 }
295