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