8150731: Nashorn JSObject linker should be exposed as a service provider
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
19f9ce673f
commit
89cdc7ca82
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.api.linker;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinker;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
|
||||
/**
|
||||
* This linker exporter is a service provider that exports Nashorn Dynalink
|
||||
* linkers to external users. Other languague runtimes that use Dynalink
|
||||
* can use the linkers exported by this provider to support tight integration
|
||||
* of Nashorn objects.
|
||||
*/
|
||||
public final class NashornLinkerExporter extends GuardingDynamicLinkerExporter {
|
||||
/**
|
||||
* The default constructor.
|
||||
*/
|
||||
public NashornLinkerExporter() {}
|
||||
|
||||
/**
|
||||
* Returns a list of exported nashorn specific linkers.
|
||||
*
|
||||
* @return list of exported nashorn specific linkers
|
||||
*/
|
||||
@Override
|
||||
public List<GuardingDynamicLinker> get() {
|
||||
return Bootstrap.getExposedLinkers();
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.DynamicLinker;
|
||||
import jdk.dynalink.DynamicLinkerFactory;
|
||||
@ -70,6 +72,7 @@ public final class Bootstrap {
|
||||
private static final BeansLinker beansLinker = new BeansLinker(Bootstrap::createMissingMemberHandler);
|
||||
private static final GuardingDynamicLinker[] prioritizedLinkers;
|
||||
private static final GuardingDynamicLinker[] fallbackLinkers;
|
||||
|
||||
static {
|
||||
final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(beansLinker);
|
||||
prioritizedLinkers = new GuardingDynamicLinker[] {
|
||||
@ -89,6 +92,19 @@ public final class Bootstrap {
|
||||
private Bootstrap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of exposed nashorn dynalink linkers.
|
||||
*
|
||||
* @return a list of exposed nashorn dynalink linkers.
|
||||
*/
|
||||
public static List<GuardingDynamicLinker> getExposedLinkers() {
|
||||
// we have to create BeansLinker without nashorn specific missing member handler!
|
||||
// Or else, we'd return values such as 'undefined' to the external world!
|
||||
final NashornBeansLinker nbl = new NashornBeansLinker(new BeansLinker());
|
||||
final JSObjectLinker linker = new JSObjectLinker(nbl);
|
||||
return Collections.singletonList(linker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Nashorn dynamic linker with the given app class loader.
|
||||
* @param appLoader the app class loader. It will be used to discover
|
||||
|
@ -71,6 +71,9 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception {
|
||||
final Object self = request.getReceiver();
|
||||
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
|
||||
if (self == null || !canLinkTypeStatic(self.getClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GuardedInvocation inv;
|
||||
if (self instanceof JSObject) {
|
||||
@ -82,7 +85,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
inv = new GuardedInvocation(beanInv.getInvocation(),
|
||||
NashornGuards.combineGuards(beanInv.getGuard(), NashornGuards.getNotJSObjectGuard()));
|
||||
} else {
|
||||
throw new AssertionError(); // Should never reach here.
|
||||
throw new AssertionError("got instanceof: " + self.getClass()); // Should never reach here.
|
||||
}
|
||||
|
||||
return Bootstrap.asTypeSafeReturn(inv, linkerServices, desc);
|
||||
|
@ -38,6 +38,10 @@ module jdk.scripting.nashorn {
|
||||
exports jdk.nashorn.tools to
|
||||
jdk.scripting.nashorn.shell;
|
||||
|
||||
provides javax.script.ScriptEngineFactory with jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
provides javax.script.ScriptEngineFactory
|
||||
with jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
|
||||
provides jdk.dynalink.linker.GuardingDynamicLinkerExporter
|
||||
with jdk.nashorn.api.linker.NashornLinkerExporter;
|
||||
}
|
||||
|
||||
|
@ -30,10 +30,13 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.List;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.DynamicLinker;
|
||||
import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.NoSuchDynamicMethodException;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.Operation;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinker;
|
||||
@ -41,6 +44,7 @@ import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
import jdk.dynalink.support.SimpleRelinkableCallSite;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.nashorn.api.scripting.AbstractJSObject;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@ -254,4 +258,55 @@ public class DynamicLinkerFactoryTest {
|
||||
|
||||
Assert.assertTrue(reachedAutoLinker);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nashornExportedLinkerJSObjectTest() {
|
||||
final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
|
||||
final DynamicLinker linker = factory.createLinker();
|
||||
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
|
||||
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
|
||||
MethodHandles.publicLookup(), op, mt)));
|
||||
final boolean[] reachedGetMember = new boolean[1];
|
||||
// check that the nashorn exported linker can be used for user defined JSObject
|
||||
Object obj = new AbstractJSObject() {
|
||||
@Override
|
||||
public Object getMember(String name) {
|
||||
reachedGetMember[0] = true;
|
||||
return name.equals("foo")? "bar" : "<unknown>";
|
||||
}
|
||||
};
|
||||
|
||||
Object value = null;
|
||||
try {
|
||||
value = cs.getTarget().invoke(obj);
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
Assert.assertTrue(reachedGetMember[0]);
|
||||
Assert.assertEquals(value, "bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nashornExportedLinkerScriptObjectMirrorTest() {
|
||||
final DynamicLinkerFactory factory = newDynamicLinkerFactory(false);
|
||||
final DynamicLinker linker = factory.createLinker();
|
||||
|
||||
// check that the nashorn exported linker can be used for ScriptObjectMirror
|
||||
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
|
||||
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
|
||||
MethodHandles.publicLookup(), op, mt)));
|
||||
Object value = null;
|
||||
try {
|
||||
final Object obj = engine.eval("({ foo: 'hello' })");
|
||||
value = cs.getTarget().invoke(obj);
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
Assert.assertEquals(value, "hello");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user