1 /* 2 * Copyright (c) 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.dynalink.beans.test; 26 27 import static jdk.dynalink.StandardNamespace.ELEMENT; 28 import static jdk.dynalink.StandardNamespace.METHOD; 29 import static jdk.dynalink.StandardNamespace.PROPERTY; 30 import static jdk.dynalink.StandardOperation.CALL; 31 import static jdk.dynalink.StandardOperation.GET; 32 import static jdk.dynalink.StandardOperation.NEW; 33 import static jdk.dynalink.StandardOperation.REMOVE; 34 import static jdk.dynalink.StandardOperation.SET; 35 36 import java.lang.invoke.CallSite; 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodHandles; 39 import java.lang.invoke.MethodType; 40 import java.security.AccessControlException; 41 import java.util.ArrayList; 42 import java.util.Date; 43 import java.util.HashMap; 44 import java.util.List; 45 import java.util.Map; 46 import jdk.dynalink.CallSiteDescriptor; 47 import jdk.dynalink.DynamicLinker; 48 import jdk.dynalink.DynamicLinkerFactory; 49 import jdk.dynalink.NamedOperation; 50 import jdk.dynalink.NoSuchDynamicMethodException; 51 import jdk.dynalink.Operation; 52 import jdk.dynalink.beans.BeansLinker; 53 import jdk.dynalink.beans.StaticClass; 54 import jdk.dynalink.support.SimpleRelinkableCallSite; 55 import org.testng.Assert; 56 import org.testng.annotations.AfterTest; 57 import org.testng.annotations.BeforeTest; 58 import org.testng.annotations.DataProvider; 59 import org.testng.annotations.Test; 60 61 public class BeanLinkerTest { 62 63 private DynamicLinker linker; 64 private static final MethodHandles.Lookup MY_LOOKUP = MethodHandles.lookup(); 65 66 @SuppressWarnings("unused") 67 @DataProvider flags()68 private static Object[][] flags() { 69 return new Object[][]{ 70 {Boolean.FALSE}, 71 {Boolean.TRUE} 72 }; 73 } 74 75 // helpers to create callsite objects createCallSite(final boolean publicLookup, final Operation op, final MethodType mt)76 private CallSite createCallSite(final boolean publicLookup, final Operation op, final MethodType mt) { 77 return linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( 78 publicLookup ? MethodHandles.publicLookup() : MY_LOOKUP, op, mt))); 79 } 80 createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt)81 private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) { 82 return createCallSite(publicLookup, op.named(name), mt); 83 } 84 createGetMethodCallSite(final boolean publicLookup, final String name)85 private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) { 86 return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class)); 87 } 88 89 private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds"); 90 private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds"); 91 92 private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); 93 private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT); 94 private static final Operation GET_METHOD = GET.withNamespace(METHOD); 95 private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT); 96 private static final Operation REMOVE_ELEMENT = REMOVE.withNamespace(ELEMENT); 97 findThrower(final String name)98 private static final MethodHandle findThrower(final String name) { 99 try { 100 return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name, 101 MethodType.methodType(Object.class, Object.class, Object.class)); 102 } catch (NoSuchMethodException | IllegalAccessException e) { 103 Assert.fail("Unexpected exception", e); 104 return null; 105 } 106 } 107 throwArrayIndexOutOfBounds(final Object receiver, final Object index)108 private static Object throwArrayIndexOutOfBounds(final Object receiver, final Object index) { 109 throw new ArrayIndexOutOfBoundsException(String.valueOf(index)); 110 } 111 throwIndexOutOfBounds(final Object receiver, final Object index)112 private static Object throwIndexOutOfBounds(final Object receiver, final Object index) { 113 throw new IndexOutOfBoundsException(String.valueOf(index)); 114 } 115 116 @BeforeTest initLinker()117 public void initLinker() { 118 final DynamicLinkerFactory factory = new DynamicLinkerFactory(); 119 factory.setFallbackLinkers(new BeansLinker((req, services) -> { 120 // This is a MissingMemberHandlerFactory that creates a missing 121 // member handler for element getters and setters that throw an 122 // ArrayIndexOutOfBoundsException when applied to an array and an 123 // IndexOutOfBoundsException when applied to a list. 124 125 final CallSiteDescriptor desc = req.getCallSiteDescriptor(); 126 final Operation op = desc.getOperation(); 127 final Operation baseOp = NamedOperation.getBaseOperation(op); 128 if (baseOp != GET_ELEMENT && baseOp != SET_ELEMENT && baseOp != REMOVE_ELEMENT) { 129 // We only handle GET_ELEMENT, SET_ELEMENT and REMOVE_ELEMENT. 130 return null; 131 } 132 133 final Object receiver = req.getReceiver(); 134 Assert.assertNotNull(receiver); 135 136 final Class<?> clazz = receiver.getClass(); 137 final MethodHandle throwerHandle; 138 if (clazz.isArray()) { 139 throwerHandle = throwArrayIndexOutOfBounds; 140 } else if (List.class.isAssignableFrom(clazz)) { 141 throwerHandle = throwIndexOutOfBounds; 142 } else { 143 Assert.fail("Unexpected receiver type " + clazz.getName()); 144 return null; 145 } 146 147 final Object name = NamedOperation.getName(op); 148 final MethodHandle nameBoundHandle; 149 if (name == null) { 150 nameBoundHandle = throwerHandle; 151 } else { 152 // If the operation is for a fixed index, bind it 153 nameBoundHandle = MethodHandles.insertArguments(throwerHandle, 1, name); 154 } 155 156 final MethodType callSiteType = desc.getMethodType(); 157 final MethodHandle arityMatchedHandle; 158 if (baseOp == SET_ELEMENT) { 159 // Drop "value" parameter for a setter 160 final int handleArity = nameBoundHandle.type().parameterCount(); 161 arityMatchedHandle = MethodHandles.dropArguments(nameBoundHandle, 162 handleArity, callSiteType.parameterType(handleArity)); 163 } else { 164 arityMatchedHandle = nameBoundHandle; 165 } 166 167 return arityMatchedHandle.asType(callSiteType); 168 })); 169 this.linker = factory.createLinker(); 170 } 171 172 @AfterTest afterTest()173 public void afterTest() { 174 this.linker = null; 175 } 176 177 @Test(dataProvider = "flags") getPropertyTest(final boolean publicLookup)178 public void getPropertyTest(final boolean publicLookup) throws Throwable { 179 final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); 180 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 181 Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class); 182 Assert.assertEquals(cs.getTarget().invoke(new Date(), "class"), Date.class); 183 } 184 185 @Test(dataProvider = "flags") getPropertyNegativeTest(final boolean publicLookup)186 public void getPropertyNegativeTest(final boolean publicLookup) throws Throwable { 187 final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); 188 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 189 Assert.assertNull(cs.getTarget().invoke(new Object(), "DOES_NOT_EXIST")); 190 } 191 192 @Test(dataProvider = "flags") getPropertyTest2(final boolean publicLookup)193 public void getPropertyTest2(final boolean publicLookup) throws Throwable { 194 final MethodType mt = MethodType.methodType(Object.class, Object.class); 195 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "class", mt); 196 Assert.assertEquals(cs.getTarget().invoke(new Object()), Object.class); 197 Assert.assertEquals(cs.getTarget().invoke(new Date()), Date.class); 198 } 199 200 @Test(dataProvider = "flags") getPropertyNegativeTest2(final boolean publicLookup)201 public void getPropertyNegativeTest2(final boolean publicLookup) throws Throwable { 202 final MethodType mt = MethodType.methodType(Object.class, Object.class); 203 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "DOES_NOT_EXIST", mt); 204 205 try { 206 cs.getTarget().invoke(new Object()); 207 throw new RuntimeException("Expected NoSuchDynamicMethodException"); 208 } catch (final Throwable th) { 209 Assert.assertTrue(th instanceof NoSuchDynamicMethodException); 210 } 211 } 212 213 @Test(dataProvider = "flags") getLengthPropertyTest(final boolean publicLookup)214 public void getLengthPropertyTest(final boolean publicLookup) throws Throwable { 215 final MethodType mt = MethodType.methodType(int.class, Object.class, String.class); 216 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); 217 218 Assert.assertEquals((int) cs.getTarget().invoke(new int[10], "length"), 10); 219 Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33); 220 } 221 222 @Test(dataProvider = "flags") getElementTest(final boolean publicLookup)223 public void getElementTest(final boolean publicLookup) throws Throwable { 224 final MethodType mt = MethodType.methodType(int.class, Object.class, int.class); 225 final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt); 226 227 final int[] arr = {23, 42}; 228 Assert.assertEquals((int) cs.getTarget().invoke(arr, 0), 23); 229 Assert.assertEquals((int) cs.getTarget().invoke(arr, 1), 42); 230 try { 231 final int x = (int) cs.getTarget().invoke(arr, -1); 232 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 233 } catch (final ArrayIndexOutOfBoundsException ex) { 234 } 235 236 try { 237 final int x = (int) cs.getTarget().invoke(arr, arr.length); 238 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 239 } catch (final ArrayIndexOutOfBoundsException ex) { 240 } 241 242 final List<Integer> list = new ArrayList<>(); 243 list.add(23); 244 list.add(430); 245 list.add(-4354); 246 Assert.assertEquals((int) cs.getTarget().invoke(list, 0), (int) list.get(0)); 247 Assert.assertEquals((int) cs.getTarget().invoke(list, 1), (int) list.get(1)); 248 Assert.assertEquals((int) cs.getTarget().invoke(list, 2), (int) list.get(2)); 249 try { 250 cs.getTarget().invoke(list, -1); 251 throw new RuntimeException("expected IndexOutOfBoundsException"); 252 } catch (final IndexOutOfBoundsException ex) { 253 } 254 255 try { 256 cs.getTarget().invoke(list, list.size()); 257 throw new RuntimeException("expected IndexOutOfBoundsException"); 258 } catch (final IndexOutOfBoundsException ex) { 259 } 260 } 261 invokeWithFixedKey(boolean publicLookup, Operation op, Object name, MethodType mt, Object... args)262 private Object invokeWithFixedKey(boolean publicLookup, Operation op, Object name, MethodType mt, Object... args) throws Throwable { 263 return createCallSite(publicLookup, op.named(name), mt).getTarget().invokeWithArguments(args); 264 } 265 266 @Test(dataProvider = "flags") getElementWithFixedKeyTest(final boolean publicLookup)267 public void getElementWithFixedKeyTest(final boolean publicLookup) throws Throwable { 268 final MethodType mt = MethodType.methodType(int.class, Object.class); 269 270 final int[] arr = {23, 42}; 271 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 0, mt, arr), 23); 272 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 1, mt, arr), 42); 273 try { 274 invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, arr); 275 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 276 } catch (final ArrayIndexOutOfBoundsException ex) { 277 } 278 279 try { 280 invokeWithFixedKey(publicLookup, GET_ELEMENT, arr.length, mt, arr); 281 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 282 } catch (final ArrayIndexOutOfBoundsException ex) { 283 } 284 285 final List<Integer> list = new ArrayList<>(); 286 list.add(23); 287 list.add(430); 288 list.add(-4354); 289 for (int i = 0; i < 3; ++i) { 290 Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, i, mt, list), (int) list.get(i)); 291 } 292 try { 293 invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, list); 294 throw new RuntimeException("expected IndexOutOfBoundsException"); 295 } catch (final IndexOutOfBoundsException ex) { 296 } 297 298 try { 299 invokeWithFixedKey(publicLookup, GET_ELEMENT, list.size(), mt, list); 300 throw new RuntimeException("expected IndexOutOfBoundsException"); 301 } catch (final IndexOutOfBoundsException ex) { 302 } 303 } 304 305 @Test(dataProvider = "flags") setElementTest(final boolean publicLookup)306 public void setElementTest(final boolean publicLookup) throws Throwable { 307 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class, int.class); 308 final CallSite cs = createCallSite(publicLookup, SET_ELEMENT, mt); 309 310 final int[] arr = {23, 42}; 311 cs.getTarget().invoke(arr, 0, 0); 312 Assert.assertEquals(arr[0], 0); 313 cs.getTarget().invoke(arr, 1, -5); 314 Assert.assertEquals(arr[1], -5); 315 316 try { 317 cs.getTarget().invoke(arr, -1, 12); 318 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 319 } catch (final ArrayIndexOutOfBoundsException ex) { 320 } 321 322 try { 323 cs.getTarget().invoke(arr, arr.length, 20); 324 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 325 } catch (final ArrayIndexOutOfBoundsException ex) { 326 } 327 328 final List<Integer> list = new ArrayList<>(); 329 list.add(23); 330 list.add(430); 331 list.add(-4354); 332 333 cs.getTarget().invoke(list, 0, -list.get(0)); 334 Assert.assertEquals((int) list.get(0), -23); 335 cs.getTarget().invoke(list, 1, -430); 336 Assert.assertEquals((int) list.get(1), -430); 337 cs.getTarget().invoke(list, 2, 4354); 338 Assert.assertEquals((int) list.get(2), 4354); 339 try { 340 cs.getTarget().invoke(list, -1, 343); 341 throw new RuntimeException("expected IndexOutOfBoundsException"); 342 } catch (final IndexOutOfBoundsException ex) { 343 } 344 345 try { 346 cs.getTarget().invoke(list, list.size(), 43543); 347 throw new RuntimeException("expected IndexOutOfBoundsException"); 348 } catch (final IndexOutOfBoundsException ex) { 349 } 350 } 351 352 @Test(dataProvider = "flags") setElementWithFixedKeyTest(final boolean publicLookup)353 public void setElementWithFixedKeyTest(final boolean publicLookup) throws Throwable { 354 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class); 355 356 final int[] arr = {23, 42}; 357 invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, arr, 0); 358 Assert.assertEquals(arr[0], 0); 359 invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, arr, -5); 360 Assert.assertEquals(arr[1], -5); 361 362 try { 363 invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, arr, 12); 364 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 365 } catch (final ArrayIndexOutOfBoundsException ex) { 366 } 367 368 try { 369 invokeWithFixedKey(publicLookup, SET_ELEMENT, arr.length, mt, arr, 20); 370 throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); 371 } catch (final ArrayIndexOutOfBoundsException ex) { 372 } 373 374 final List<Integer> list = new ArrayList<>(); 375 list.add(23); 376 list.add(430); 377 list.add(-4354); 378 379 invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, list, -list.get(0)); 380 Assert.assertEquals((int) list.get(0), -23); 381 invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, list, -430); 382 Assert.assertEquals((int) list.get(1), -430); 383 invokeWithFixedKey(publicLookup, SET_ELEMENT, 2, mt, list, 4354); 384 Assert.assertEquals((int) list.get(2), 4354); 385 try { 386 invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, list, 343); 387 throw new RuntimeException("expected IndexOutOfBoundsException"); 388 } catch (final IndexOutOfBoundsException ex) { 389 } 390 391 try { 392 invokeWithFixedKey(publicLookup, SET_ELEMENT, list.size(), mt, list, 43543); 393 throw new RuntimeException("expected IndexOutOfBoundsException"); 394 } catch (final IndexOutOfBoundsException ex) { 395 } 396 } 397 398 @Test(dataProvider = "flags") newObjectTest(final boolean publicLookup)399 public void newObjectTest(final boolean publicLookup) { 400 final MethodType mt = MethodType.methodType(Object.class, Object.class); 401 final CallSite cs = createCallSite(publicLookup, NEW, mt); 402 403 Object obj = null; 404 try { 405 obj = cs.getTarget().invoke(StaticClass.forClass(Date.class)); 406 } catch (final Throwable th) { 407 throw new RuntimeException(th); 408 } 409 410 Assert.assertTrue(obj instanceof Date); 411 } 412 413 @Test(dataProvider = "flags") staticPropertyTest(final boolean publicLookup)414 public void staticPropertyTest(final boolean publicLookup) { 415 final MethodType mt = MethodType.methodType(Object.class, Class.class); 416 final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "static", mt); 417 418 Object obj = null; 419 try { 420 obj = cs.getTarget().invoke(Object.class); 421 } catch (final Throwable th) { 422 throw new RuntimeException(th); 423 } 424 425 Assert.assertTrue(obj instanceof StaticClass); 426 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object.class); 427 428 try { 429 obj = cs.getTarget().invoke(Date.class); 430 } catch (final Throwable th) { 431 throw new RuntimeException(th); 432 } 433 434 Assert.assertTrue(obj instanceof StaticClass); 435 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Date.class); 436 437 try { 438 obj = cs.getTarget().invoke(Object[].class); 439 } catch (final Throwable th) { 440 throw new RuntimeException(th); 441 } 442 443 Assert.assertTrue(obj instanceof StaticClass); 444 Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object[].class); 445 } 446 447 @Test(dataProvider = "flags") instanceMethodCallTest(final boolean publicLookup)448 public void instanceMethodCallTest(final boolean publicLookup) { 449 final CallSite cs = createGetMethodCallSite(publicLookup, "getClass"); 450 final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class); 451 final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); 452 453 Object method = null; 454 try { 455 method = cs.getTarget().invoke(new Date()); 456 } catch (final Throwable th) { 457 throw new RuntimeException(th); 458 } 459 460 Assert.assertNotNull(method); 461 Assert.assertTrue(BeansLinker.isDynamicMethod(method)); 462 Class clz = null; 463 try { 464 clz = (Class) cs2.getTarget().invoke(method, new Date()); 465 } catch (final Throwable th) { 466 throw new RuntimeException(th); 467 } 468 469 Assert.assertEquals(clz, Date.class); 470 } 471 472 @Test(dataProvider = "flags") staticMethodCallTest(final boolean publicLookup)473 public void staticMethodCallTest(final boolean publicLookup) { 474 final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty"); 475 final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class); 476 final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); 477 478 Object method = null; 479 try { 480 method = cs.getTarget().invoke(StaticClass.forClass(System.class)); 481 } catch (final Throwable th) { 482 throw new RuntimeException(th); 483 } 484 485 Assert.assertNotNull(method); 486 Assert.assertTrue(BeansLinker.isDynamicMethod(method)); 487 488 String str = null; 489 try { 490 str = (String) cs2.getTarget().invoke(method, null, "os.name"); 491 } catch (final Throwable th) { 492 throw new RuntimeException(th); 493 } 494 Assert.assertEquals(str, System.getProperty("os.name")); 495 } 496 497 // try calling System.getenv and expect security exception 498 @Test(dataProvider = "flags") systemGetenvTest(final boolean publicLookup)499 public void systemGetenvTest(final boolean publicLookup) { 500 final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv"); 501 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class)); 502 503 try { 504 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 505 cs2.getTarget().invoke(method, StaticClass.forClass(System.class)); 506 throw new RuntimeException("should not reach here in any case!"); 507 } catch (final Throwable th) { 508 Assert.assertTrue(th instanceof SecurityException); 509 } 510 } 511 512 // try getting a specific sensitive System property and expect security exception 513 @Test(dataProvider = "flags") systemGetPropertyTest(final boolean publicLookup)514 public void systemGetPropertyTest(final boolean publicLookup) { 515 final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty"); 516 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class)); 517 518 try { 519 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 520 cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home"); 521 throw new RuntimeException("should not reach here in any case!"); 522 } catch (final Throwable th) { 523 Assert.assertTrue(th instanceof SecurityException); 524 } 525 } 526 527 // check a @CallerSensitive API and expect appropriate access check exception 528 @Test(dataProvider = "flags") systemLoadLibraryTest(final boolean publicLookup)529 public void systemLoadLibraryTest(final boolean publicLookup) { 530 final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary"); 531 final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class)); 532 533 try { 534 final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); 535 cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo"); 536 throw new RuntimeException("should not reach here in any case!"); 537 } catch (final Throwable th) { 538 if (publicLookup) { 539 Assert.assertTrue(th instanceof IllegalAccessError); 540 } else { 541 Assert.assertTrue(th instanceof AccessControlException); 542 } 543 } 544 } 545 546 @Test(dataProvider = "flags") removeElementFromListTest(final boolean publicLookup)547 public void removeElementFromListTest(final boolean publicLookup) throws Throwable { 548 final MethodType mt = MethodType.methodType(void.class, Object.class, int.class); 549 final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt); 550 551 final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354)); 552 553 cs.getTarget().invoke(list, 1); 554 Assert.assertEquals(list, List.of(23, -4354)); 555 cs.getTarget().invoke(list, 1); 556 Assert.assertEquals(list, List.of(23)); 557 cs.getTarget().invoke(list, 0); 558 Assert.assertEquals(list, List.of()); 559 try { 560 cs.getTarget().invoke(list, -1); 561 throw new RuntimeException("expected IndexOutOfBoundsException"); 562 } catch (final IndexOutOfBoundsException ex) { 563 } 564 565 try { 566 cs.getTarget().invoke(list, list.size()); 567 throw new RuntimeException("expected IndexOutOfBoundsException"); 568 } catch (final IndexOutOfBoundsException ex) { 569 } 570 } 571 572 @Test(dataProvider = "flags") removeElementFromListWithFixedKeyTest(final boolean publicLookup)573 public void removeElementFromListWithFixedKeyTest(final boolean publicLookup) throws Throwable { 574 final MethodType mt = MethodType.methodType(void.class, Object.class); 575 576 final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354)); 577 578 createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list); 579 Assert.assertEquals(list, List.of(23, -4354)); 580 createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list); 581 Assert.assertEquals(list, List.of(23)); 582 createCallSite(publicLookup, REMOVE_ELEMENT.named(0), mt).getTarget().invoke(list); 583 Assert.assertEquals(list, List.of()); 584 try { 585 createCallSite(publicLookup, REMOVE_ELEMENT.named(-1), mt).getTarget().invoke(list); 586 throw new RuntimeException("expected IndexOutOfBoundsException"); 587 } catch (final IndexOutOfBoundsException ex) { 588 } 589 590 try { 591 createCallSite(publicLookup, REMOVE_ELEMENT.named(list.size()), mt).getTarget().invoke(list); 592 throw new RuntimeException("expected IndexOutOfBoundsException"); 593 } catch (final IndexOutOfBoundsException ex) { 594 } 595 } 596 597 @Test(dataProvider = "flags") removeElementFromMapTest(final boolean publicLookup)598 public void removeElementFromMapTest(final boolean publicLookup) throws Throwable { 599 final MethodType mt = MethodType.methodType(void.class, Object.class, Object.class); 600 final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt); 601 602 final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3")); 603 604 cs.getTarget().invoke(map, "k2"); 605 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 606 cs.getTarget().invoke(map, "k4"); 607 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 608 cs.getTarget().invoke(map, "k1"); 609 Assert.assertEquals(map, Map.of("k3", "v3")); 610 } 611 612 613 @Test(dataProvider = "flags") removeElementFromMapWithFixedKeyTest(final boolean publicLookup)614 public void removeElementFromMapWithFixedKeyTest(final boolean publicLookup) throws Throwable { 615 final MethodType mt = MethodType.methodType(void.class, Object.class); 616 617 final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3")); 618 619 createCallSite(publicLookup, REMOVE_ELEMENT.named("k2"), mt).getTarget().invoke(map); 620 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 621 createCallSite(publicLookup, REMOVE_ELEMENT.named("k4"), mt).getTarget().invoke(map); 622 Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3")); 623 createCallSite(publicLookup, REMOVE_ELEMENT.named("k1"), mt).getTarget().invoke(map); 624 Assert.assertEquals(map, Map.of("k3", "v3")); 625 } 626 } 627