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