8252124: Restore Dynalink tests

Reviewed-by: sundar
This commit is contained in:
Attila Szegedi 2020-08-23 14:58:59 +02:00
parent e4eaa2377b
commit 97f8261e41
14 changed files with 1892 additions and 0 deletions

View File

@ -295,6 +295,7 @@ jdk_other = \
javax/smartcardio \
javax/xml \
-javax/xml/crypto \
jdk/dynalink \
jdk/internal/jline \
com/sun/jndi \
lib/testlibrary

View File

@ -0,0 +1,631 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.dynalink.StandardNamespace.ELEMENT;
import static jdk.dynalink.StandardNamespace.METHOD;
import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.CALL;
import static jdk.dynalink.StandardOperation.GET;
import static jdk.dynalink.StandardOperation.NEW;
import static jdk.dynalink.StandardOperation.REMOVE;
import static jdk.dynalink.StandardOperation.SET;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.NoSuchDynamicMethodException;
import jdk.dynalink.Operation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* @test
* @run testng/othervm/java.security.policy=untrusted.security.policy BeanLinkerTest
*/
public class BeanLinkerTest {
private DynamicLinker linker;
private static final MethodHandles.Lookup MY_LOOKUP = MethodHandles.lookup();
@SuppressWarnings("unused")
@DataProvider
private static Object[][] flags() {
return new Object[][]{
{Boolean.FALSE},
{Boolean.TRUE}
};
}
// helpers to create callsite objects
private CallSite createCallSite(final boolean publicLookup, final Operation op, final MethodType mt) {
return linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
publicLookup ? MethodHandles.publicLookup() : MY_LOOKUP, op, mt)));
}
private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) {
return createCallSite(publicLookup, op.named(name), mt);
}
private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) {
return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class));
}
private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds");
private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds");
private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT);
private static final Operation GET_METHOD = GET.withNamespace(METHOD);
private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT);
private static final Operation REMOVE_ELEMENT = REMOVE.withNamespace(ELEMENT);
private static MethodHandle findThrower(final String name) {
try {
return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name,
MethodType.methodType(Object.class, Object.class, Object.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
Assert.fail("Unexpected exception", e);
return null;
}
}
private static Object throwArrayIndexOutOfBounds(final Object receiver, final Object index) {
throw new ArrayIndexOutOfBoundsException(String.valueOf(index));
}
private static Object throwIndexOutOfBounds(final Object receiver, final Object index) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
@BeforeTest
public void initLinker() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setFallbackLinkers(new BeansLinker((req, services) -> {
// This is a MissingMemberHandlerFactory that creates a missing
// member handler for element getters and setters that throw an
// ArrayIndexOutOfBoundsException when applied to an array and an
// IndexOutOfBoundsException when applied to a list.
final CallSiteDescriptor desc = req.getCallSiteDescriptor();
final Operation op = desc.getOperation();
final Operation baseOp = NamedOperation.getBaseOperation(op);
if (baseOp != GET_ELEMENT && baseOp != SET_ELEMENT && baseOp != REMOVE_ELEMENT) {
// We only handle GET_ELEMENT, SET_ELEMENT and REMOVE_ELEMENT.
return null;
}
final Object receiver = req.getReceiver();
Assert.assertNotNull(receiver);
final Class<?> clazz = receiver.getClass();
final MethodHandle throwerHandle;
if (clazz.isArray()) {
throwerHandle = throwArrayIndexOutOfBounds;
} else if (List.class.isAssignableFrom(clazz)) {
throwerHandle = throwIndexOutOfBounds;
} else if (Map.class.isAssignableFrom(clazz)) {
return null;
} else {
Assert.fail("Unexpected receiver type " + clazz.getName());
return null;
}
final Object name = NamedOperation.getName(op);
final MethodHandle nameBoundHandle;
if (name == null) {
nameBoundHandle = throwerHandle;
} else {
// If the operation is for a fixed index, bind it
nameBoundHandle = MethodHandles.insertArguments(throwerHandle, 1, name);
}
final MethodType callSiteType = desc.getMethodType();
final MethodHandle arityMatchedHandle;
if (baseOp == SET_ELEMENT) {
// Drop "value" parameter for a setter
final int handleArity = nameBoundHandle.type().parameterCount();
arityMatchedHandle = MethodHandles.dropArguments(nameBoundHandle,
handleArity, callSiteType.parameterType(handleArity));
} else {
arityMatchedHandle = nameBoundHandle;
}
return arityMatchedHandle.asType(callSiteType);
}));
this.linker = factory.createLinker();
}
@AfterTest
public void afterTest() {
this.linker = null;
}
@Test(dataProvider = "flags")
public void getPropertyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
Assert.assertEquals(cs.getTarget().invoke(new Date(), "class"), Date.class);
}
@Test(dataProvider = "flags")
public void getPropertyNegativeTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
Assert.assertNull(cs.getTarget().invoke(new Object(), "DOES_NOT_EXIST"));
}
@Test(dataProvider = "flags")
public void getPropertyTest2(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "class", mt);
Assert.assertEquals(cs.getTarget().invoke(new Object()), Object.class);
Assert.assertEquals(cs.getTarget().invoke(new Date()), Date.class);
}
@Test(dataProvider = "flags")
public void getPropertyNegativeTest2(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "DOES_NOT_EXIST", mt);
try {
cs.getTarget().invoke(new Object());
throw new RuntimeException("Expected NoSuchDynamicMethodException");
} catch (final Throwable th) {
Assert.assertTrue(th instanceof NoSuchDynamicMethodException);
}
}
@Test(dataProvider = "flags")
public void getLengthPropertyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(int.class, Object.class, String.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
Assert.assertEquals((int) cs.getTarget().invoke(new int[10], "length"), 10);
Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33);
}
@Test(dataProvider = "flags")
public void getElementTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(int.class, Object.class, int.class);
final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt);
final int[] arr = {23, 42};
Assert.assertEquals((int) cs.getTarget().invoke(arr, 0), 23);
Assert.assertEquals((int) cs.getTarget().invoke(arr, 1), 42);
try {
final int x = (int) cs.getTarget().invoke(arr, -1);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
try {
final int x = (int) cs.getTarget().invoke(arr, arr.length);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
final List<Integer> list = new ArrayList<>();
list.add(23);
list.add(430);
list.add(-4354);
Assert.assertEquals((int) cs.getTarget().invoke(list, 0), (int) list.get(0));
Assert.assertEquals((int) cs.getTarget().invoke(list, 1), (int) list.get(1));
Assert.assertEquals((int) cs.getTarget().invoke(list, 2), (int) list.get(2));
try {
cs.getTarget().invoke(list, -1);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
cs.getTarget().invoke(list, list.size());
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
private Object invokeWithFixedKey(boolean publicLookup, Operation op, Object name, MethodType mt, Object... args) throws Throwable {
return createCallSite(publicLookup, op.named(name), mt).getTarget().invokeWithArguments(args);
}
@Test(dataProvider = "flags")
public void getElementWithFixedKeyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(int.class, Object.class);
final int[] arr = {23, 42};
Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 0, mt, arr), 23);
Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, 1, mt, arr), 42);
try {
invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, arr);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
try {
invokeWithFixedKey(publicLookup, GET_ELEMENT, arr.length, mt, arr);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
final List<Integer> list = new ArrayList<>();
list.add(23);
list.add(430);
list.add(-4354);
for (int i = 0; i < 3; ++i) {
Assert.assertEquals((int) invokeWithFixedKey(publicLookup, GET_ELEMENT, i, mt, list), (int) list.get(i));
}
try {
invokeWithFixedKey(publicLookup, GET_ELEMENT, -1, mt, list);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
invokeWithFixedKey(publicLookup, GET_ELEMENT, list.size(), mt, list);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
@Test(dataProvider = "flags")
public void setElementTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class, int.class, int.class);
final CallSite cs = createCallSite(publicLookup, SET_ELEMENT, mt);
final int[] arr = {23, 42};
cs.getTarget().invoke(arr, 0, 0);
Assert.assertEquals(arr[0], 0);
cs.getTarget().invoke(arr, 1, -5);
Assert.assertEquals(arr[1], -5);
try {
cs.getTarget().invoke(arr, -1, 12);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
try {
cs.getTarget().invoke(arr, arr.length, 20);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
final List<Integer> list = new ArrayList<>();
list.add(23);
list.add(430);
list.add(-4354);
cs.getTarget().invoke(list, 0, -list.get(0));
Assert.assertEquals((int) list.get(0), -23);
cs.getTarget().invoke(list, 1, -430);
Assert.assertEquals((int) list.get(1), -430);
cs.getTarget().invoke(list, 2, 4354);
Assert.assertEquals((int) list.get(2), 4354);
try {
cs.getTarget().invoke(list, -1, 343);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
cs.getTarget().invoke(list, list.size(), 43543);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
@Test(dataProvider = "flags")
public void setElementWithFixedKeyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class, int.class);
final int[] arr = {23, 42};
invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, arr, 0);
Assert.assertEquals(arr[0], 0);
invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, arr, -5);
Assert.assertEquals(arr[1], -5);
try {
invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, arr, 12);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
try {
invokeWithFixedKey(publicLookup, SET_ELEMENT, arr.length, mt, arr, 20);
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
} catch (final ArrayIndexOutOfBoundsException ex) {
}
final List<Integer> list = new ArrayList<>();
list.add(23);
list.add(430);
list.add(-4354);
invokeWithFixedKey(publicLookup, SET_ELEMENT, 0, mt, list, -list.get(0));
Assert.assertEquals((int) list.get(0), -23);
invokeWithFixedKey(publicLookup, SET_ELEMENT, 1, mt, list, -430);
Assert.assertEquals((int) list.get(1), -430);
invokeWithFixedKey(publicLookup, SET_ELEMENT, 2, mt, list, 4354);
Assert.assertEquals((int) list.get(2), 4354);
try {
invokeWithFixedKey(publicLookup, SET_ELEMENT, -1, mt, list, 343);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
invokeWithFixedKey(publicLookup, SET_ELEMENT, list.size(), mt, list, 43543);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
@Test(dataProvider = "flags")
public void newObjectTest(final boolean publicLookup) {
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final CallSite cs = createCallSite(publicLookup, NEW, mt);
Object obj = null;
try {
obj = cs.getTarget().invoke(StaticClass.forClass(Date.class));
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertTrue(obj instanceof Date);
}
@Test(dataProvider = "flags")
public void staticPropertyTest(final boolean publicLookup) {
final MethodType mt = MethodType.methodType(Object.class, Class.class);
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "static", mt);
Object obj = null;
try {
obj = cs.getTarget().invoke(Object.class);
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertTrue(obj instanceof StaticClass);
Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object.class);
try {
obj = cs.getTarget().invoke(Date.class);
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertTrue(obj instanceof StaticClass);
Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Date.class);
try {
obj = cs.getTarget().invoke(Object[].class);
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertTrue(obj instanceof StaticClass);
Assert.assertEquals(((StaticClass) obj).getRepresentedClass(), Object[].class);
}
@Test(dataProvider = "flags")
public void instanceMethodCallTest(final boolean publicLookup) {
final CallSite cs = createGetMethodCallSite(publicLookup, "getClass");
final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class);
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
Object method = null;
try {
method = cs.getTarget().invoke(new Date());
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertNotNull(method);
Assert.assertTrue(BeansLinker.isDynamicMethod(method));
Class clz = null;
try {
clz = (Class) cs2.getTarget().invoke(method, new Date());
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertEquals(clz, Date.class);
}
@Test(dataProvider = "flags")
public void staticMethodCallTest(final boolean publicLookup) {
final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty");
final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class);
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
Object method = null;
try {
method = cs.getTarget().invoke(StaticClass.forClass(System.class));
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertNotNull(method);
Assert.assertTrue(BeansLinker.isDynamicMethod(method));
String str = null;
try {
str = (String) cs2.getTarget().invoke(method, null, "os.name");
} catch (final Throwable th) {
throw new RuntimeException(th);
}
Assert.assertEquals(str, System.getProperty("os.name"));
}
// try calling System.getenv and expect security exception
@Test(dataProvider = "flags")
public void systemGetenvTest(final boolean publicLookup) {
final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv");
final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class));
try {
final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
cs2.getTarget().invoke(method, StaticClass.forClass(System.class));
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
Assert.assertTrue(th instanceof SecurityException);
}
}
// try getting a specific sensitive System property and expect security exception
@Test(dataProvider = "flags")
public void systemGetPropertyTest(final boolean publicLookup) {
final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty");
final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class));
try {
final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home");
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
Assert.assertTrue(th instanceof SecurityException);
}
}
// check a @CallerSensitive API and expect appropriate access check exception
@Test(dataProvider = "flags")
public void systemLoadLibraryTest(final boolean publicLookup) {
final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary");
final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class));
try {
final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo");
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
if (publicLookup) {
Assert.assertTrue(th instanceof IllegalAccessError);
} else {
Assert.assertTrue(th instanceof AccessControlException, "Expected AccessControlException, got " + th.getClass().getName());
}
}
}
@Test(dataProvider = "flags")
public void removeElementFromListTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class, int.class);
final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt);
final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354));
cs.getTarget().invoke(list, 1);
Assert.assertEquals(list, List.of(23, -4354));
cs.getTarget().invoke(list, 1);
Assert.assertEquals(list, List.of(23));
cs.getTarget().invoke(list, 0);
Assert.assertEquals(list, List.of());
try {
cs.getTarget().invoke(list, -1);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
cs.getTarget().invoke(list, list.size());
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
@Test(dataProvider = "flags")
public void removeElementFromListWithFixedKeyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class);
final List<Integer> list = new ArrayList<>(List.of(23, 430, -4354));
createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list);
Assert.assertEquals(list, List.of(23, -4354));
createCallSite(publicLookup, REMOVE_ELEMENT.named(1), mt).getTarget().invoke(list);
Assert.assertEquals(list, List.of(23));
createCallSite(publicLookup, REMOVE_ELEMENT.named(0), mt).getTarget().invoke(list);
Assert.assertEquals(list, List.of());
try {
createCallSite(publicLookup, REMOVE_ELEMENT.named(-1), mt).getTarget().invoke(list);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
try {
createCallSite(publicLookup, REMOVE_ELEMENT.named(list.size()), mt).getTarget().invoke(list);
throw new RuntimeException("expected IndexOutOfBoundsException");
} catch (final IndexOutOfBoundsException ex) {
}
}
@Test(dataProvider = "flags")
public void removeElementFromMapTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class, Object.class);
final CallSite cs = createCallSite(publicLookup, REMOVE_ELEMENT, mt);
final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3"));
cs.getTarget().invoke(map, "k2");
Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3"));
cs.getTarget().invoke(map, "k4");
Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3"));
cs.getTarget().invoke(map, "k1");
Assert.assertEquals(map, Map.of("k3", "v3"));
}
@Test(dataProvider = "flags")
public void removeElementFromMapWithFixedKeyTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(void.class, Object.class);
final Map<String, String> map = new HashMap<>(Map.of("k1", "v1", "k2", "v2", "k3", "v3"));
createCallSite(publicLookup, REMOVE_ELEMENT.named("k2"), mt).getTarget().invoke(map);
Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3"));
createCallSite(publicLookup, REMOVE_ELEMENT.named("k4"), mt).getTarget().invoke(map);
Assert.assertEquals(map, Map.of("k1", "v1", "k3", "v3"));
createCallSite(publicLookup, REMOVE_ELEMENT.named("k1"), mt).getTarget().invoke(map);
Assert.assertEquals(map, Map.of("k3", "v3"));
}
}

View File

@ -0,0 +1,333 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.dynalink.StandardNamespace.ELEMENT;
import static jdk.dynalink.StandardNamespace.METHOD;
import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.CALL;
import static jdk.dynalink.StandardOperation.GET;
import static jdk.dynalink.StandardOperation.SET;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.Namespace;
import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.NoSuchDynamicMethodException;
import jdk.dynalink.Operation;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @test
* @run testng BeansLinkerTest
*/
public class BeansLinkerTest {
public static class Bean1 {
public final int answer = 42;
public String getName() {
return "bean1";
}
public String someMethod(final String x) {
return x + "-foo";
}
}
@Test
public static void testPublicFieldPropertyUnnamedGetter() {
testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
}
@Test
public static void testPublicFieldPropertyNamedGetter() {
testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op.named("answer"), new Bean1())));
}
@Test
public static void testGetterPropertyUnnamedGetter() {
testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
}
@Test
public static void testGetterPropertyNamedGetter() {
testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op.named("name"), new Bean1())));
}
@Test
public static void testMethodUnnamedGetter() {
testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
}
@Test
public static void testMethodNamedGetter() {
testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op.named("someMethod"), new Bean1()), new Bean1(), "bar")));
}
private static final Map<String, String> MAP1 = new HashMap<>();
static {
MAP1.put("foo", "bar");
}
@Test
public static void testElementUnnamedGetter() {
testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
}
@Test
public static void testElementNamedGetter() {
testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op.named("foo"), MAP1)));
}
public static class Bean2 {
public int answer;
private String name;
public void setName(final String name) {
this.name = name;
}
}
@Test
public static void testUnnamedFieldSetter() {
testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op, bean2, "answer", 12);
Assert.assertEquals(bean2.answer, 12);
});
}
@Test
public static void testNamedFieldSetter() {
testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op.named("answer"), bean2, 14);
Assert.assertEquals(bean2.answer, 14);
});
}
@Test
public static void testUnnamedPropertySetter() {
testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op, bean2, "name", "boo");
Assert.assertEquals(bean2.name, "boo");
});
}
@Test
public static void testNamedPropertySetter() {
testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op.named("name"), bean2, "blah");
Assert.assertEquals(bean2.name, "blah");
});
}
private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*ELEMENT.*PROPERTY.*");
@Test
public static void testUnnamedElementAndPropertyGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op, map, "empty")));
}
@Test
public static void testNamedElementAndPropertyGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op.named("empty"), map)));
}
private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*PROPERTY.*ELEMENT.*");
@Test
public static void testUnnamedPropertyAndElementGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op, map, "empty")));
}
@Test
public static void testNamedPropertyAndElementGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op.named("empty"), map)));
}
public static class MapWithProperty extends HashMap<String, Object> {
private String name;
public void setName(final String name) {
this.name = name;
}
}
@Test
public static void testUnnamedPropertyAndElementSetter() {
final MapWithProperty map = new MapWithProperty();
map.put("name", "element");
call(SET.withNamespaces(PROPERTY, ELEMENT), map, "name", "property");
Assert.assertEquals("property", map.name);
Assert.assertEquals("element", map.get("name"));
call(SET.withNamespaces(ELEMENT, PROPERTY), map, "name", "element2");
Assert.assertEquals("property", map.name);
Assert.assertEquals("element2", map.get("name"));
}
@Test
public static void testMissingMembersAtLinkTime() {
testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object())));
testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object(), "newValue")));
}
@Test
public static void testMissingMembersAtRunTime() {
call(GET.withNamespace(ELEMENT), new ArrayList<>(), "foo");
Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> {
testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));});
// No assertion for the setter; we just expect it to silently succeed
testPermutations(SETTER_PERMUTATIONS, (op) -> call(op, receiver, "foo", "newValue"));
});
}
public static class A {
public static class Inner {}
}
public static class B extends A {
public static class Inner {}
}
@Test
public static void testInnerClassGetter() {
Object inner1 = call(GET.withNamespace(PROPERTY), StaticClass.forClass(A.class), "Inner");
Assert.assertTrue(inner1 instanceof StaticClass);
Assert.assertEquals(A.Inner.class, ((StaticClass) inner1).getRepresentedClass());
Object inner2 = call(GET.withNamespace(PROPERTY), StaticClass.forClass(B.class), "Inner");
Assert.assertTrue(inner2 instanceof StaticClass);
Assert.assertEquals(B.Inner.class, ((StaticClass) inner2).getRepresentedClass());
}
private static void expectNoSuchDynamicMethodException(final Runnable r) {
try {
r.run();
Assert.fail("Should've thrown NoSuchDynamicMethodException");
} catch(final NoSuchDynamicMethodException e) {
}
}
private static final NamespaceOperation[] GETTER_PERMUTATIONS = new NamespaceOperation[] {
GET.withNamespaces(PROPERTY),
GET.withNamespaces(METHOD),
GET.withNamespaces(ELEMENT),
GET.withNamespaces(PROPERTY, ELEMENT),
GET.withNamespaces(PROPERTY, METHOD),
GET.withNamespaces(ELEMENT, PROPERTY),
GET.withNamespaces(ELEMENT, METHOD),
GET.withNamespaces(METHOD, PROPERTY),
GET.withNamespaces(METHOD, ELEMENT),
GET.withNamespaces(PROPERTY, ELEMENT, METHOD),
GET.withNamespaces(PROPERTY, METHOD, ELEMENT),
GET.withNamespaces(ELEMENT, PROPERTY, METHOD),
GET.withNamespaces(ELEMENT, METHOD, PROPERTY),
GET.withNamespaces(METHOD, PROPERTY, ELEMENT),
GET.withNamespaces(METHOD, ELEMENT, PROPERTY)
};
private static final NamespaceOperation[] SETTER_PERMUTATIONS = new NamespaceOperation[] {
SET.withNamespaces(PROPERTY),
SET.withNamespaces(ELEMENT),
SET.withNamespaces(PROPERTY, ELEMENT),
SET.withNamespaces(ELEMENT, PROPERTY)
};
private static void testPermutations(final NamespaceOperation[] ops, final Operation requiredOp, final Namespace requiredNamespace, final int expectedCount, final Consumer<NamespaceOperation> test) {
testPermutationsWithFilter(ops, (op)->NamespaceOperation.contains(op, requiredOp, requiredNamespace), expectedCount, test);
}
private static void testPermutations(final NamespaceOperation[] ops, final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
}
private static void testPermutations(final NamespaceOperation[] ops, final Consumer<NamespaceOperation> test) {
testPermutationsWithFilter(ops, (op)->true, ops.length, test);
}
private static void testPermutationsWithFilter(final NamespaceOperation[] ops, final Predicate<NamespaceOperation> filter, final int expectedCount, final Consumer<NamespaceOperation> test) {
final int[] counter = new int[1];
Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
Assert.assertEquals(counter[0], expectedCount);
}
private static void testGetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
testPermutations(GETTER_PERMUTATIONS, GET, requiredNamespace, 11, test);
}
private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test);
}
private static void testSetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
testPermutations(SETTER_PERMUTATIONS, SET, requiredNamespace, 3, test);
}
private static Object call(final Operation op, final Object... args) {
try {
return new DynamicLinkerFactory().createLinker().link(
new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), op, t(args.length))))
.dynamicInvoker().invokeWithArguments(args);
} catch (final Error|RuntimeException e) {
throw e;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
}
private static Object call(final Object... args) {
return call(CALL, args);
}
private static MethodType t(final int argCount) {
return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class));
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.GET;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.Operation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @test
* @run testng CallSiteTest
*/
public class CallSiteTest {
private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
@Test
public void testInitialize() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] initializeCalled = { Boolean.FALSE };
linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), GET_PROPERTY.named("DO_NOT_CARE"), mt)) {
@Override
public void initialize(final MethodHandle relinkAndInvoke) {
initializeCalled[0] = Boolean.TRUE;
super.initialize(relinkAndInvoke);
}
});
Assert.assertTrue(initializeCalled[0]);
}
@Test
public void testRelink() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] relinkCalled = { Boolean.FALSE };
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), GET_PROPERTY.named("class"), mt)) {
@Override
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
relinkCalled[0] = Boolean.TRUE;
super.relink(guardedInvocation, relinkAndInvoke);
}
});
Assert.assertFalse(relinkCalled[0]);
try {
cs.getTarget().invoke(new Object());
} catch (final Throwable th) {}
Assert.assertTrue(relinkCalled[0]);
}
@Test
public void testResetAndRelink() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setUnstableRelinkThreshold(1);
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] resetAndRelinkCalled = { Boolean.FALSE };
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), GET_PROPERTY.named("length"), mt)) {
@Override
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
resetAndRelinkCalled[0] = Boolean.TRUE;
super.resetAndRelink(guardedInvocation, relinkAndInvoke);
}
});
Assert.assertFalse(resetAndRelinkCalled[0]);
try {
cs.getTarget().invoke(new Object[] {});
} catch (final Throwable th) {}
Assert.assertFalse(resetAndRelinkCalled[0]);
try {
cs.getTarget().invoke(new ArrayList<Object>());
} catch (final Throwable th) {}
Assert.assertTrue(resetAndRelinkCalled[0]);
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.dynalink.beans.BeansLinker;
import org.testng.annotations.Test;
/**
* @test
* @build ClassLoaderAware
* @run testng CallerSensitiveTest
*/
public class CallerSensitiveTest {
@Test
public void testCallerSensitive() {
new BeansLinker().getLinkerForClass(ClassLoaderAware.class);
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public interface ClassLoaderAware {
public ClassLoader getContextClassLoader();
public void checkMemberAccess(Class<?> clazz, int which);
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.Operation;
import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardingDynamicLinker;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @test
* @run testng LinkedCallSiteLocationTest
*/
public class LinkedCallSiteLocationTest {
private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD);
@Test
public void testLinkedCallSiteLocation() throws Throwable {
final StackTraceElement[] lastLinked = new StackTraceElement[1];
final GuardingDynamicLinker testLinker =
(r, s) -> { lastLinked[0] = DynamicLinker.getLinkedCallSiteLocation(); return null; };
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setPrioritizedLinker(testLinker);
final DynamicLinker linker = factory.createLinker();
final SimpleRelinkableCallSite callSite = new SimpleRelinkableCallSite(
new CallSiteDescriptor(
MethodHandles.lookup(),
GET_METHOD.named("foo"),
MethodType.methodType(void.class, Object.class)));
linker.link(callSite);
// Test initial linking
callSite.dynamicInvoker().invoke(new TestClass1()); final int l1 = getLineNumber();
assertLocation(lastLinked[0], l1);
// Test relinking
callSite.dynamicInvoker().invoke(new TestClass2()); final int l2 = getLineNumber();
assertLocation(lastLinked[0], l2);
}
private void assertLocation(final StackTraceElement frame, final int lineNumber) {
Assert.assertNotNull(frame);
Assert.assertEquals(frame.getLineNumber(), lineNumber);
Assert.assertEquals(frame.getClassName(), this.getClass().getName());
}
private static int getLineNumber() {
return StackWalker.getInstance().walk(s -> s.skip(1).findFirst().get().getLineNumber());
}
public static class TestClass1 {
public void foo() {
}
}
public static class TestClass2 {
public void foo() {
}
}
}

View File

@ -0,0 +1,273 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.linker.support.Lookup;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* @test
* @run testng LookupTest
*/
public class LookupTest {
private static final MethodHandles.Lookup MY_LOOKUP = MethodHandles.lookup();
private static MethodHandles.Lookup getLookup(final boolean publicLookup) {
return publicLookup? MethodHandles.publicLookup() : MY_LOOKUP;
}
// test constructors, methods used for lookup
@SuppressWarnings("unused")
public LookupTest() {}
@SuppressWarnings("unused")
private LookupTest(final int unused) {}
@SuppressWarnings("unused")
private void privateFunc() {}
@SuppressWarnings("unused")
protected void protectedFunc() {}
@SuppressWarnings("unused")
private static void privateStaticFunc() {}
@SuppressWarnings("unused")
private final int myIntField = 0;
@SuppressWarnings("unused")
@DataProvider
private static Object[][] flags() {
return new Object[][]{
{Boolean.FALSE},
{Boolean.TRUE}
};
}
@Test(dataProvider = "flags")
public void unreflectTest(final boolean publicLookup) throws NoSuchMethodException {
final MethodHandle mh = Lookup.unreflect(getLookup(publicLookup), LookupTest.class.getMethod("unreflectTest", Boolean.TYPE));
Assert.assertNotNull(mh);
}
@Test
public void unreflectTest2() throws NoSuchMethodException {
final MethodHandle mh = Lookup.PUBLIC.unreflect(LookupTest.class.getMethod("unreflectTest", Boolean.TYPE));
Assert.assertNotNull(mh);
}
@Test(dataProvider = "flags")
public void unreflectNegativeTest(final boolean publicLookup) throws NoSuchMethodException {
try {
final MethodHandle mh = Lookup.unreflect(getLookup(publicLookup),
LookupTest.class.getDeclaredMethod("privateFunc"));
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void unreflectNegativeTest2() throws NoSuchMethodException {
try {
Lookup.PUBLIC.unreflect(LookupTest.class.getDeclaredMethod("privateFunc"));
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void unreflectConstructorTest(final boolean publicLookup) throws NoSuchMethodException {
final MethodHandle mh = Lookup.unreflectConstructor(getLookup(publicLookup), LookupTest.class.getConstructor());
Assert.assertNotNull(mh);
}
@Test
public void unreflectConstructorTest2() throws NoSuchMethodException {
final MethodHandle mh = Lookup.PUBLIC.unreflectConstructor(LookupTest.class.getConstructor());
Assert.assertNotNull(mh);
}
@Test(dataProvider = "flags")
public void unreflectConstructorNegativeTest(final boolean publicLookup) throws NoSuchMethodException {
try {
final MethodHandle mh = Lookup.unreflectConstructor(getLookup(publicLookup),
LookupTest.class.getDeclaredConstructor(Integer.TYPE));
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void unreflectConstructorNegativeTest2() throws NoSuchMethodException {
try {
Lookup.PUBLIC.unreflectConstructor(
LookupTest.class.getDeclaredConstructor(Integer.TYPE));
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void findOwnStaticTest(final boolean publicLookup) {
try {
final MethodHandle mh = Lookup.findOwnStatic(getLookup(publicLookup), "getLookup",
MethodHandles.Lookup.class, Boolean.TYPE);
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void findOwnStaticTest2() {
try {
Lookup.PUBLIC.findStatic(LookupTest.class, "getLookup",
MethodType.methodType(MethodHandles.Lookup.class, Boolean.TYPE));
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void findOwnSepcialTest(final boolean publicLookup) {
try {
final MethodHandle mh = Lookup.findOwnSpecial(getLookup(publicLookup), "privateFunc", Void.TYPE);
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void findOwnSepcialTest2() {
try {
Lookup.PUBLIC.findOwnSpecial("privateFunc", Void.TYPE);
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void findGetterTest(final boolean publicLookup) {
try {
final MethodHandle mh = new Lookup(getLookup(publicLookup)).findGetter(LookupTest.class, "myIntField", Integer.TYPE);
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void findGetterTest2() {
try {
Lookup.PUBLIC.findGetter(LookupTest.class, "myIntField", Integer.TYPE);
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void findVirtualTest(final boolean publicLookup) {
try {
final MethodHandle mh = new Lookup(getLookup(publicLookup)).findVirtual(LookupTest.class, "protectedFunc",
MethodType.methodType(Void.TYPE));
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void findVirtualTest2() {
try {
Lookup.PUBLIC.findVirtual(LookupTest.class, "protectedFunc",
MethodType.methodType(Void.TYPE));
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test(dataProvider = "flags")
public void findStaticTest(final boolean publicLookup) {
try {
final MethodHandle mh = new Lookup(getLookup(publicLookup)).findStatic(LookupTest.class, "privateStaticFunc",
MethodType.methodType(Void.TYPE));
if (publicLookup) {
throw new RuntimeException("should have thrown Error");
}
Assert.assertNotNull(mh);
} catch (final Error err) {
Assert.assertTrue(publicLookup);
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
@Test
public void findStaticTest2() {
try {
Lookup.PUBLIC.findStatic(LookupTest.class, "privateStaticFunc",
MethodType.methodType(Void.TYPE));
throw new RuntimeException("should have thrown Error");
} catch (final Error err) {
Assert.assertTrue(err instanceof NoSuchMethodError || err instanceof IllegalAccessError);
}
}
}

View File

@ -0,0 +1 @@
TestGuardingDynamicLinkerExporter

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.linker.GuardingDynamicLinker;
import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.LinkerServices;
/**
* A trusted linker exporter (build file gives appropriate permission to the jar containing this class!).
*/
public final class TestGuardingDynamicLinkerExporter extends GuardingDynamicLinkerExporter {
private static final ThreadLocal<CallSiteDescriptor> lastDescriptor = new ThreadLocal<>();
private static boolean enabled = false;
public static void enable() {
reset(true);
}
public static void disable() {
reset(false);
}
public static boolean isLastCallSiteDescriptor(final CallSiteDescriptor desc) {
return lastDescriptor.get() == desc;
}
private static void reset(final boolean enable) {
lastDescriptor.set(null);
enabled = enable;
}
@Override
public List<GuardingDynamicLinker> get() {
return List.of(((final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
if (enabled) {
lastDescriptor.set(linkRequest.getCallSiteDescriptor());
}
return null;
}));
}
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.GET;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.NoSuchDynamicMethodException;
import jdk.dynalink.Operation;
import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.LinkerServices;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @test
* @build TestGuardingDynamicLinkerExporter
* @run testng/othervm/java.security.policy=trusted.security.policy TrustedDynamicLinkerFactoryTest
*/
public class TrustedDynamicLinkerFactoryTest {
private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
private static DynamicLinkerFactory newDynamicLinkerFactory(final boolean resetClassLoader) {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
if (resetClassLoader) {
factory.setClassLoader(null);
}
return factory;
}
@Test
public void callSiteCreationTest() {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final DynamicLinker linker = factory.createLinker();
final StandardOperation[] operations = StandardOperation.values();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
for (final Operation op : operations) {
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), op, mt)));
Assert.assertNotNull(cs);
Assert.assertEquals(cs.type(), mt);
Assert.assertNotNull(cs.getTarget());
}
}
@Test
public void fallbackLinkerTest() {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final Operation myOperation = new Operation() {
};
final boolean[] reachedFallback = { false };
factory.setFallbackLinkers((final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
reachedFallback[0] = true;
return null;
});
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class);
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), myOperation, mt)));
// linking the call site initially does not invoke the linkers!
Assert.assertFalse(reachedFallback[0]);
try {
cs.getTarget().invoke();
} catch (final NoSuchDynamicMethodException nsdm) {
// we do expect NoSuchDynamicMethod!
// because our dummy fallback linker returns null!
} catch (final Throwable th) {
throw new RuntimeException("should not reach here with: " + th);
}
// check that the control reached fallback linker!
Assert.assertTrue(reachedFallback[0]);
}
@Test
public void priorityLinkerTest() {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final Operation myOperation = new Operation() {
};
final boolean[] reachedProrityLinker = { false };
factory.setPrioritizedLinker((final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
reachedProrityLinker[0] = true;
return null;
});
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class);
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), myOperation, mt)));
// linking the call site initially does not invoke the linkers!
Assert.assertFalse(reachedProrityLinker[0]);
try {
cs.getTarget().invoke();
} catch (final NoSuchDynamicMethodException nsdm) {
// we do expect NoSuchDynamicMethod!
// because our dummy priority linker returns null!
} catch (final Throwable th) {
throw new RuntimeException("should not reach here with: " + th);
}
// check that the control reached fallback linker!
Assert.assertTrue(reachedProrityLinker[0]);
}
@Test
public void priorityAndFallbackLinkerTest() {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final Operation myOperation = new Operation() {
};
final int[] linkerReachCounter = { 0 };
factory.setPrioritizedLinker((final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
linkerReachCounter[0]++;
return null;
});
factory.setFallbackLinkers((final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
Assert.assertEquals(linkRequest.getCallSiteDescriptor().getOperation(), myOperation);
Assert.assertEquals(linkerReachCounter[0], 1);
linkerReachCounter[0]++;
return null;
});
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class);
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), myOperation, mt)));
// linking the call site initially does not invoke the linkers!
Assert.assertEquals(linkerReachCounter[0], 0);
try {
cs.getTarget().invoke();
} catch (final NoSuchDynamicMethodException nsdm) {
// we do expect NoSuchDynamicMethod!
} catch (final Throwable th) {
throw new RuntimeException("should not reach here with: " + th);
}
Assert.assertEquals(linkerReachCounter[0], 2);
}
@Test
public void prelinkTransformerTest() throws Throwable {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final boolean[] reachedPrelinkTransformer = { false };
factory.setPrelinkTransformer((final GuardedInvocation inv, final LinkRequest linkRequest, final LinkerServices linkerServices) -> {
reachedPrelinkTransformer[0] = true;
// just identity transformer!
return inv;
});
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final DynamicLinker linker = factory.createLinker();
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), GET_PROPERTY, mt)));
Assert.assertFalse(reachedPrelinkTransformer[0]);
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
Assert.assertTrue(reachedPrelinkTransformer[0]);
}
@Test
public void internalObjectsFilterTest() throws Throwable {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(true);
final boolean[] reachedInternalObjectsFilter = { false };
factory.setInternalObjectsFilter((final MethodHandle mh) -> {
reachedInternalObjectsFilter[0] = true;
return mh;
});
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final DynamicLinker linker = factory.createLinker();
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), GET_PROPERTY, mt)));
Assert.assertFalse(reachedInternalObjectsFilter[0]);
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
Assert.assertTrue(reachedInternalObjectsFilter[0]);
}
@Test
public void autoLoadedLinkerTest() {
testAutoLoadedLinkerInvoked(new Object(), "toString");
}
@Test
public void autoLoadedLinkerSeesStaticMethod() {
testAutoLoadedLinkerInvoked(StaticClass.forClass(System.class), "currentTimeMillis");
}
private static void testAutoLoadedLinkerInvoked(final Object target, final String methodName) {
final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final CallSiteDescriptor testDescriptor = new CallSiteDescriptor(MethodHandles.publicLookup(),
GET.withNamespace(StandardNamespace.METHOD).named(methodName), mt);
final CallSite cs = linker.link(new SimpleRelinkableCallSite(testDescriptor));
TestGuardingDynamicLinkerExporter.enable();
try {
cs.getTarget().invoke(target);
// The linker was loaded and it observed our invocation
Assert.assertTrue(TestGuardingDynamicLinkerExporter.isLastCallSiteDescriptor(testDescriptor));
} catch (final Throwable th) {
throw new RuntimeException(th);
} finally {
TestGuardingDynamicLinkerExporter.disable();
}
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.List;
import java.util.ServiceConfigurationError;
import jdk.dynalink.DynamicLinkerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* @test
* @build TestGuardingDynamicLinkerExporter
* @run testng/othervm/java.security.policy=untrusted.security.policy UntrustedDynamicLinkerFactoryTest
*/
public class UntrustedDynamicLinkerFactoryTest {
@Test
public void autoLoadedLinkerNegativeTest() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.createLinker();
// expect one error as we have one untrusted linker exporter in META-INF/services
final List<ServiceConfigurationError> autoLoadingErrors = factory.getAutoLoadingErrors();
// single error ...
Assert.assertEquals(autoLoadingErrors.size(), 1);
autoLoadingErrors.get(0).printStackTrace();
final Throwable cause = autoLoadingErrors.get(0).getCause();
// .. due to permission check..
Assert.assertTrue(cause.toString().contains("dynalink.exportLinkersAutomatically"));
}
}

View File

@ -0,0 +1,7 @@
grant {
permission java.io.FilePermission "${user.home}/-", "read";
};
grant codeBase "file:${test.classes}/-" {
permission java.lang.RuntimePermission "dynalink.exportLinkersAutomatically";
};

View File

@ -0,0 +1,3 @@
grant {
permission java.io.FilePermission "${user.home}/-", "read";
};