8133299: Nashorn Java adapters should not early bind to functions
Reviewed-by: hannesw, lagergren, sundar
This commit is contained in:
parent
80b266507c
commit
495414b40c
@ -55,18 +55,24 @@ final class AdaptationResult {
|
||||
static final AdaptationResult SUCCESSFUL_RESULT = new AdaptationResult(Outcome.SUCCESS, "");
|
||||
|
||||
private final Outcome outcome;
|
||||
private final RuntimeException cause;
|
||||
private final String[] messageArgs;
|
||||
|
||||
AdaptationResult(final Outcome outcome, final String... messageArgs) {
|
||||
AdaptationResult(final Outcome outcome, final RuntimeException cause, final String... messageArgs) {
|
||||
this.outcome = outcome;
|
||||
this.cause = cause;
|
||||
this.messageArgs = messageArgs;
|
||||
}
|
||||
|
||||
AdaptationResult(final Outcome outcome, final String... messageArgs) {
|
||||
this(outcome, null, messageArgs);
|
||||
}
|
||||
|
||||
Outcome getOutcome() {
|
||||
return outcome;
|
||||
}
|
||||
|
||||
ECMAException typeError() {
|
||||
return ECMAErrors.typeError("extend." + outcome, messageArgs);
|
||||
return ECMAErrors.typeError(cause, "extend." + outcome, messageArgs);
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ public final class Bootstrap {
|
||||
* Create a call site and link it for Nashorn. This version of the method conforms to the invokedynamic bootstrap
|
||||
* method expected signature and is referenced from Nashorn generated bytecode as the bootstrap method for all
|
||||
* invokedynamic instructions.
|
||||
* @param lookup MethodHandle lookup. Ignored as Nashorn only uses public lookup.
|
||||
* @param lookup MethodHandle lookup.
|
||||
* @param opDesc Dynalink dynamic operation descriptor.
|
||||
* @param type Method type.
|
||||
* @param flags flags for call type, trace/profile etc.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,7 @@ import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
|
||||
|
||||
/**
|
||||
* A factory class that generates adapter classes. Adapter classes allow
|
||||
@ -211,7 +212,7 @@ public final class JavaAdapterFactory {
|
||||
* be generated from a ScriptFunction.
|
||||
*/
|
||||
static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
|
||||
return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction;
|
||||
return getAdapterInfo(new Class<?>[] { clazz }).isAutoConvertibleFromFunction();
|
||||
}
|
||||
|
||||
private static AdapterInfo getAdapterInfo(final Class<?>[] types) {
|
||||
@ -273,7 +274,7 @@ public final class JavaAdapterFactory {
|
||||
} catch (final AdaptationException e) {
|
||||
return new AdapterInfo(e.getAdaptationResult());
|
||||
} catch (final RuntimeException e) {
|
||||
return new AdapterInfo(new AdaptationResult(AdaptationResult.Outcome.ERROR_OTHER, Arrays.toString(types), e.toString()));
|
||||
return new AdapterInfo(new AdaptationResult(Outcome.ERROR_OTHER, e, Arrays.toString(types), e.toString()));
|
||||
}
|
||||
}
|
||||
}, CREATE_ADAPTER_INFO_ACC_CTXT);
|
||||
@ -319,6 +320,13 @@ public final class JavaAdapterFactory {
|
||||
getClassAdapterClass(classOverrides, protectionDomain);
|
||||
}
|
||||
|
||||
boolean isAutoConvertibleFromFunction() {
|
||||
if(adaptationResult.getOutcome() == AdaptationResult.Outcome.ERROR_OTHER) {
|
||||
throw adaptationResult.typeError();
|
||||
}
|
||||
return autoConvertibleFromFunction;
|
||||
}
|
||||
|
||||
private StaticClass getInstanceAdapterClass(final ProtectionDomain protectionDomain) {
|
||||
CodeSource codeSource = protectionDomain.getCodeSource();
|
||||
if(codeSource == null) {
|
||||
|
@ -33,8 +33,11 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.ConstantCallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSigner;
|
||||
@ -43,15 +46,18 @@ import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
|
||||
/**
|
||||
* Provides static utility services to generated Java adapter classes.
|
||||
@ -64,50 +70,47 @@ public final class JavaAdapterServices {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JS script function, binds it to null JS "this", and adapts its parameter types, return types, and arity
|
||||
* to the specified type and arity. This method is public mainly for implementation reasons, so the adapter classes
|
||||
* can invoke it from their constructors that take a ScriptFunction in its first argument to obtain the method
|
||||
* handles for their abstract method implementations.
|
||||
* @param fn the script function
|
||||
* @param type the method type it has to conform to
|
||||
* @return the appropriately adapted method handle for invoking the script function.
|
||||
* Given a script function used as a delegate for a SAM adapter, figure out
|
||||
* the right object to use as its "this" when called.
|
||||
* @param delegate the delegate function
|
||||
* @param global the current global of the adapter
|
||||
* @return either the passed global, or UNDEFINED if the function is strict.
|
||||
*/
|
||||
public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type) {
|
||||
// JS "this" will be global object or undefined depending on if 'fn' is strict or not
|
||||
return bindAndAdaptHandle(fn, fn.isStrict()? ScriptRuntime.UNDEFINED : Context.getGlobal(), type);
|
||||
public static Object getCallThis(final ScriptFunction delegate, final Object global) {
|
||||
return delegate.isStrict() ? ScriptRuntime.UNDEFINED : global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JS script object, retrieves a function from it by name, binds it to the script object as its "this", and
|
||||
* adapts its parameter types, return types, and arity to the specified type and arity. This method is public mainly
|
||||
* for implementation reasons, so the adapter classes can invoke it from their constructors that take a Object
|
||||
* in its first argument to obtain the method handles for their method implementations.
|
||||
* @param obj the script obj
|
||||
* @param name the name of the property that contains the function
|
||||
* @param type the method type it has to conform to
|
||||
* @return the appropriately adapted method handle for invoking the script function, or null if the value of the
|
||||
* property is either null or undefined, or "toString" was requested as the name, but the object doesn't directly
|
||||
* define it but just inherits it through prototype.
|
||||
* Throws a "not.an.object" type error. Used when the delegate passed to the
|
||||
* adapter constructor is not a script object.
|
||||
* @param obj the object that is not a script object.
|
||||
*/
|
||||
public static MethodHandle getHandle(final Object obj, final String name, final MethodType type) {
|
||||
if (! (obj instanceof ScriptObject)) {
|
||||
throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
|
||||
}
|
||||
public static void notAnObject(final Object obj) {
|
||||
throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
|
||||
}
|
||||
|
||||
final ScriptObject sobj = (ScriptObject)obj;
|
||||
// Since every JS Object has a toString, we only override "String toString()" it if it's explicitly specified
|
||||
if ("toString".equals(name) && !sobj.hasOwnProperty("toString")) {
|
||||
/**
|
||||
* Checks if the passed object, which is supposed to be a callee retrieved
|
||||
* through applying the GET_METHOD_PROPERTY operation on the delegate, is
|
||||
* a ScriptFunction, or null or undefined. These are the only allowed values
|
||||
* for adapter method implementations, so in case it is neither, it throws
|
||||
* a type error. Note that this restriction is somewhat artificial; as the
|
||||
* CALL dynamic operation could invoke any Nashorn callable. We are
|
||||
* restricting adapters to actual ScriptFunction objects for now though.
|
||||
* @param callee the callee to check
|
||||
* @param name the name of the function
|
||||
* @return the callee cast to a ScriptFunction, or null if it was null or undefined.
|
||||
* @throws ECMAException representing a JS TypeError with "not.a.function"
|
||||
* message if the passed callee is neither a script function, nor null, nor
|
||||
* undefined.
|
||||
*/
|
||||
public static ScriptFunction checkFunction(final Object callee, final String name) {
|
||||
if (callee instanceof ScriptFunction) {
|
||||
return (ScriptFunction)callee;
|
||||
} else if (JSType.nullOrUndefined(callee)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object fnObj = sobj.get(name);
|
||||
if (fnObj instanceof ScriptFunction) {
|
||||
return bindAndAdaptHandle((ScriptFunction)fnObj, sobj, type);
|
||||
} else if(fnObj == null || fnObj instanceof Undefined) {
|
||||
return null;
|
||||
} else {
|
||||
throw typeError("not.a.function", name);
|
||||
}
|
||||
throw typeError("not.a.function.value", name, ScriptRuntime.safeToString(callee));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,8 +119,8 @@ public final class JavaAdapterServices {
|
||||
* static initializers.
|
||||
* @return the thread-local JS object used to define methods for the class being initialized.
|
||||
*/
|
||||
public static Object getClassOverrides() {
|
||||
final Object overrides = classOverrides.get();
|
||||
public static ScriptObject getClassOverrides() {
|
||||
final ScriptObject overrides = classOverrides.get();
|
||||
assert overrides != null;
|
||||
return overrides;
|
||||
}
|
||||
@ -135,29 +138,59 @@ public final class JavaAdapterServices {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current global scope
|
||||
* @param global the global scope
|
||||
* Set the current global scope to that of the adapter global
|
||||
* @param adapterGlobal the adapter's global scope
|
||||
* @return a Runnable that when invoked restores the previous global
|
||||
*/
|
||||
public static void setGlobal(final Object global) {
|
||||
Context.setGlobal((ScriptObject)global);
|
||||
public static Runnable setGlobal(final ScriptObject adapterGlobal) {
|
||||
final Global currentGlobal = Context.getGlobal();
|
||||
if (adapterGlobal != currentGlobal) {
|
||||
Context.setGlobal(adapterGlobal);
|
||||
return ()->Context.setGlobal(currentGlobal);
|
||||
}
|
||||
return ()->{};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current global scope
|
||||
* Get the current non-null global scope
|
||||
* @return the current global scope
|
||||
* @throws NullPointerException if the current global scope is null.
|
||||
*/
|
||||
public static Object getGlobal() {
|
||||
return Context.getGlobal();
|
||||
public static ScriptObject getNonNullGlobal() {
|
||||
return Objects.requireNonNull(Context.getGlobal(), "Current global is null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the object has its own toString function. Used
|
||||
* when implementing toString for adapters. Since every JS Object has a
|
||||
* toString function, we only override "String toString()" in adapters if
|
||||
* it is explicitly specified and not inherited from a prototype.
|
||||
* @param sobj the object
|
||||
* @return true if the object has its own toString function.
|
||||
*/
|
||||
public static boolean hasOwnToString(final ScriptObject sobj) {
|
||||
// NOTE: we could just use ScriptObject.hasOwnProperty("toString"), but
|
||||
// its logic is more complex and this is what it boils down to with a
|
||||
// fixed "toString" argument.
|
||||
return sobj.getMap().findProperty("toString") != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate to {@link Bootstrap#bootstrap(Lookup, String, MethodType, int)}.
|
||||
* @param lookup MethodHandle lookup.
|
||||
* @param opDesc Dynalink dynamic operation descriptor.
|
||||
* @param type Method type.
|
||||
* @param flags flags for call type, trace/profile etc.
|
||||
* @return CallSite with MethodHandle to appropriate method or null if not found.
|
||||
*/
|
||||
public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) {
|
||||
return Bootstrap.bootstrap(lookup, opDesc, type, flags);
|
||||
}
|
||||
|
||||
static void setClassOverrides(final ScriptObject overrides) {
|
||||
classOverrides.set(overrides);
|
||||
}
|
||||
|
||||
private static MethodHandle bindAndAdaptHandle(final ScriptFunction fn, final Object self, final MethodType type) {
|
||||
return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(fn.getBoundInvokeHandle(self), type, false), type);
|
||||
}
|
||||
|
||||
private static MethodHandle createNoPermissionsInvoker() {
|
||||
final String className = "NoPermissionsInvoker";
|
||||
|
||||
@ -202,16 +235,6 @@ public final class JavaAdapterServices {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a method handle used to convert a return value from a delegate method (always Object) to the expected
|
||||
* Java return type.
|
||||
* @param returnType the return type
|
||||
* @return the converter for the expected return type
|
||||
*/
|
||||
public static MethodHandle getObjectConverter(final Class<?> returnType) {
|
||||
return Bootstrap.getLinkerServices().getTypeConverter(Object.class, returnType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when returning Object from an adapted method to filter out internal Nashorn objects that must not be seen
|
||||
* by the callers. Currently only transforms {@code ConsString} into {@code String} and transforms {@code ScriptObject} into {@code ScriptObjectMirror}.
|
||||
@ -233,13 +256,39 @@ public final class JavaAdapterServices {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to convert a return value of a delegate function to String. It is similar to
|
||||
* {@code JSType.toString(Object)}, except it doesn't handle StaticClass specially, and it returns null for null
|
||||
* input instead of the string "null".
|
||||
* @param obj the return value.
|
||||
* @return the String value of the return value
|
||||
* Returns a new {@link RuntimeException} wrapping the passed throwable.
|
||||
* Makes generated bytecode smaller by doing an INVOKESTATIC to this method
|
||||
* rather than the NEW/DUP_X1/SWAP/INVOKESPECIAL <init> sequence.
|
||||
* @param t the original throwable to wrap
|
||||
* @return a newly created runtime exception wrapping the passed throwable.
|
||||
*/
|
||||
public static String toString(final Object obj) {
|
||||
return JavaArgumentConverters.toString(obj);
|
||||
public static RuntimeException wrapThrowable(final Throwable t) {
|
||||
return new RuntimeException(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new {@link UnsupportedOperationException}. Makes
|
||||
* generated bytecode smaller by doing INVOKESTATIC to this method rather
|
||||
* than the NEW/DUP/INVOKESPECIAL <init> sequence.
|
||||
* @return a newly created {@link UnsupportedOperationException}.
|
||||
*/
|
||||
public static UnsupportedOperationException unsupported() {
|
||||
return new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* A bootstrap method used to collect invocation arguments into an Object array.
|
||||
* for variable arity invocation.
|
||||
* @param lookup the adapter's lookup (not used).
|
||||
* @param name the call site name (not used).
|
||||
* @param type the method type
|
||||
* @return a method that takes the input parameters and packs them into a
|
||||
* newly allocated Object array.
|
||||
*/
|
||||
public static CallSite createArrayBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type) {
|
||||
return new ConstantCallSite(
|
||||
MethodHandles.identity(Object[].class)
|
||||
.asCollector(Object[].class, type.parameterCount())
|
||||
.asType(type));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
package jdk.nashorn.internal.runtime.linker.test;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Supplier;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class JavaAdapterTest {
|
||||
public interface TestConversions {
|
||||
public byte getByte(byte b);
|
||||
public short getShort(short b);
|
||||
public char getChar(char c);
|
||||
public int getInt(int i);
|
||||
public float getFloat(float f);
|
||||
public long getLong(long l);
|
||||
public double getDouble(double d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testBlah() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.eval("new java.util.Comparator({})");
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testConversions() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("TestConversionsClass", TestConversions.class);
|
||||
final TestConversions tc = (TestConversions)e.eval(
|
||||
"function id(x) { return x };" +
|
||||
"new TestConversionsClass.static({" +
|
||||
" getByte: id, getShort: id, getChar: id, getInt: id," +
|
||||
" getFloat: id, getLong: id, getDouble: id });");
|
||||
|
||||
Assert.assertEquals(Byte.MIN_VALUE, tc.getByte(Byte.MIN_VALUE));
|
||||
Assert.assertEquals(Byte.MAX_VALUE, tc.getByte(Byte.MAX_VALUE));
|
||||
|
||||
Assert.assertEquals(Short.MIN_VALUE, tc.getShort(Short.MIN_VALUE));
|
||||
Assert.assertEquals(Short.MAX_VALUE, tc.getShort(Short.MAX_VALUE));
|
||||
|
||||
Assert.assertEquals(Character.MIN_VALUE, tc.getChar(Character.MIN_VALUE));
|
||||
Assert.assertEquals(Character.MAX_VALUE, tc.getChar(Character.MAX_VALUE));
|
||||
|
||||
Assert.assertEquals(Integer.MIN_VALUE, tc.getInt(Integer.MIN_VALUE));
|
||||
Assert.assertEquals(Integer.MAX_VALUE, tc.getInt(Integer.MAX_VALUE));
|
||||
|
||||
Assert.assertEquals(Long.MIN_VALUE, tc.getLong(Long.MIN_VALUE));
|
||||
Assert.assertEquals(Long.MAX_VALUE, tc.getLong(Long.MAX_VALUE));
|
||||
|
||||
Assert.assertEquals(Float.MIN_VALUE, tc.getFloat(Float.MIN_VALUE));
|
||||
Assert.assertEquals(Float.MAX_VALUE, tc.getFloat(Float.MAX_VALUE));
|
||||
Assert.assertEquals(Float.MIN_NORMAL, tc.getFloat(Float.MIN_NORMAL));
|
||||
Assert.assertEquals(Float.POSITIVE_INFINITY, tc.getFloat(Float.POSITIVE_INFINITY));
|
||||
Assert.assertEquals(Float.NEGATIVE_INFINITY, tc.getFloat(Float.NEGATIVE_INFINITY));
|
||||
Assert.assertTrue(Float.isNaN(tc.getFloat(Float.NaN)));
|
||||
|
||||
Assert.assertEquals(Double.MIN_VALUE, tc.getDouble(Double.MIN_VALUE));
|
||||
Assert.assertEquals(Double.MAX_VALUE, tc.getDouble(Double.MAX_VALUE));
|
||||
Assert.assertEquals(Double.MIN_NORMAL, tc.getDouble(Double.MIN_NORMAL));
|
||||
Assert.assertEquals(Double.POSITIVE_INFINITY, tc.getDouble(Double.POSITIVE_INFINITY));
|
||||
Assert.assertEquals(Double.NEGATIVE_INFINITY, tc.getDouble(Double.NEGATIVE_INFINITY));
|
||||
Assert.assertTrue(Double.isNaN(tc.getDouble(Double.NaN)));
|
||||
}
|
||||
|
||||
private static ScriptEngine createEngine() {
|
||||
// Use no optimistic typing so we run faster; short-running tests.
|
||||
return new NashornScriptEngineFactory().getScriptEngine("-ot=false");
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testUnimplemented() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
final Runnable r = (Runnable) e.eval("new java.lang.Runnable({})");
|
||||
Assert.assertNull(Context.getGlobal());
|
||||
try {
|
||||
r.run();
|
||||
Assert.fail();
|
||||
} catch(final UnsupportedOperationException x) {
|
||||
// This is expected
|
||||
}
|
||||
// Check global has been restored
|
||||
Assert.assertNull(Context.getGlobal());
|
||||
}
|
||||
|
||||
public interface ThrowingRunnable {
|
||||
public void run() throws Throwable;
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testUnimplementedWithThrowable() throws Throwable {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("ThrowingRunnableClass", ThrowingRunnable.class);
|
||||
final ThrowingRunnable r = (ThrowingRunnable) e.eval("new ThrowingRunnableClass.static({})");
|
||||
Assert.assertNull(Context.getGlobal());
|
||||
try {
|
||||
r.run();
|
||||
Assert.fail();
|
||||
} catch(final UnsupportedOperationException x) {
|
||||
// This is expected
|
||||
}
|
||||
// Check global has been restored
|
||||
Assert.assertNull(Context.getGlobal());
|
||||
}
|
||||
|
||||
public interface IntSupplierWithDefault {
|
||||
public default int get() { return 42; }
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testUnimplementedWithDefault() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("IntSupplierWithDefault", IntSupplierWithDefault.class);
|
||||
final IntSupplierWithDefault s1 = (IntSupplierWithDefault) e.eval("new IntSupplierWithDefault.static({})");
|
||||
Assert.assertEquals(42, s1.get());
|
||||
final IntSupplierWithDefault s2 = (IntSupplierWithDefault) e.eval("new IntSupplierWithDefault.static({ get: function() { return 43 }})");
|
||||
Assert.assertEquals(43, s2.get());
|
||||
}
|
||||
|
||||
public interface SupplierSupplier {
|
||||
public Supplier<Object> getSupplier();
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testReturnAdapter() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("SupplierSupplier", SupplierSupplier.class);
|
||||
final SupplierSupplier s = (SupplierSupplier) e.eval("new SupplierSupplier.static(function(){ return function() { return 'foo' } })");
|
||||
Assert.assertEquals("foo", s.getSupplier().get());
|
||||
}
|
||||
|
||||
public interface MaxParams {
|
||||
public Object method(boolean p1, byte p2, short p3, char p4, int p5, float p6, long p7, double p8,
|
||||
Object p9, Object p10, Object p11, Object p12, Object p13, Object p14, Object p15, Object p16,
|
||||
Object p17, Object p18, Object p19, Object p20, Object p21, Object p22, Object p23, Object p24,
|
||||
Object p25, Object p26, Object p27, Object p28, Object p29, Object p30, Object p31, Object p32,
|
||||
Object p33, Object p34, Object p35, Object p36, Object p37, Object p38, Object p39, Object p40,
|
||||
Object p41, Object p42, Object p43, Object p44, Object p45, Object p46, Object p47, Object p48,
|
||||
Object p49, Object p50, Object p51, Object p52, Object p53, Object p54, Object p55, Object p56,
|
||||
Object p57, Object p58, Object p59, Object p60, Object p61, Object p62, Object p63, Object p64,
|
||||
Object p65, Object p66, Object p67, Object p68, Object p69, Object p70, Object p71, Object p72,
|
||||
Object p73, Object p74, Object p75, Object p76, Object p77, Object p78, Object p79, Object p80,
|
||||
Object p81, Object p82, Object p83, Object p84, Object p85, Object p86, Object p87, Object p88,
|
||||
Object p89, Object p90, Object p91, Object p92, Object p93, Object p94, Object p95, Object p96,
|
||||
Object p97, Object p98, Object p99, Object p100, Object p101, Object p102, Object p103, Object p104,
|
||||
Object p105, Object p106, Object p107, Object p108, Object p109, Object p110, Object p111, Object p112,
|
||||
Object p113, Object p114, Object p115, Object p116, Object p117, Object p118, Object p119, Object p120,
|
||||
Object p121, Object p122, Object p123, Object p124, Object p125, Object p126, Object p127, Object p128,
|
||||
Object p129, Object p130, Object p131, Object p132, Object p133, Object p134, Object p135, Object p136,
|
||||
Object p137, Object p138, Object p139, Object p140, Object p141, Object p142, Object p143, Object p144,
|
||||
Object p145, Object p146, Object p147, Object p148, Object p149, Object p150, Object p151, Object p152,
|
||||
Object p153, Object p154, Object p155, Object p156, Object p157, Object p158, Object p159, Object p160,
|
||||
Object p161, Object p162, Object p163, Object p164, Object p165, Object p166, Object p167, Object p168,
|
||||
Object p169, Object p170, Object p171, Object p172, Object p173, Object p174, Object p175, Object p176,
|
||||
Object p177, Object p178, Object p179, Object p180, Object p181, Object p182, Object p183, Object p184,
|
||||
Object p185, Object p186, Object p187, Object p188, Object p189, Object p190, Object p191, Object p192,
|
||||
Object p193, Object p194, Object p195, Object p196, Object p197, Object p198, Object p199, Object p200,
|
||||
Object p201, Object p202, Object p203, Object p204, Object p205, Object p206, Object p207, Object p208,
|
||||
Object p209, Object p210, Object p211, Object p212, Object p213, Object p214, Object p215, Object p216,
|
||||
Object p217, Object p218, Object p219, Object p220, Object p221, Object p222, Object p223, Object p224,
|
||||
Object p225, Object p226, Object p227, Object p228, Object p229, Object p230, Object p231, Object p232,
|
||||
Object p233, Object p234, Object p235, Object p236, Object p237, Object p238, Object p239, Object p240,
|
||||
Object p241, Object p242, Object p243, Object p244, Object p245, Object p246, Object p247, Object p248,
|
||||
Object p249, Object p250, Object p251, Object p252);
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testMaxLengthAdapter() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("MaxParams", MaxParams.class);
|
||||
final MaxParams s = (MaxParams) e.eval("new MaxParams.static(function(){ return arguments })");
|
||||
final ScriptObjectMirror m = (ScriptObjectMirror)s.method(true, Byte.MIN_VALUE, Short.MIN_VALUE, 'a', Integer.MAX_VALUE, Float.MAX_VALUE, Long.MAX_VALUE, Double.MAX_VALUE,
|
||||
"8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26",
|
||||
"27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44",
|
||||
"45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62",
|
||||
"63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80",
|
||||
"81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98",
|
||||
"99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114",
|
||||
"115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130",
|
||||
"131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146",
|
||||
"147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162",
|
||||
"163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178",
|
||||
"179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194",
|
||||
"195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210",
|
||||
"211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226",
|
||||
"227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242",
|
||||
"243", "244", "245", "246", "247", "248", "249", "250", "251");
|
||||
Assert.assertEquals(true, m.getSlot(0));
|
||||
Assert.assertEquals(Integer.valueOf(Byte.MIN_VALUE), m.getSlot(1)); // Byte becomes Integer
|
||||
Assert.assertEquals(Integer.valueOf(Short.MIN_VALUE), m.getSlot(2)); // Short becomes Integer
|
||||
Assert.assertEquals(Character.valueOf('a'), m.getSlot(3));
|
||||
Assert.assertEquals(Integer.valueOf(Integer.MAX_VALUE), m.getSlot(4));
|
||||
Assert.assertEquals(Double.valueOf(Float.MAX_VALUE), m.getSlot(5)); // Float becomes Double
|
||||
Assert.assertEquals(Long.valueOf(Long.MAX_VALUE), m.getSlot(6)); // Long was untouched
|
||||
Assert.assertEquals(Double.valueOf(Double.MAX_VALUE), m.getSlot(7));
|
||||
for (int i = 8; i < 252; ++i) {
|
||||
Assert.assertEquals(String.valueOf(i), m.getSlot(i));
|
||||
}
|
||||
}
|
||||
|
||||
public interface TestScriptObjectMirror {
|
||||
public JSObject getJSObject();
|
||||
public ScriptObjectMirror getScriptObjectMirror();
|
||||
public Map<Object, Object> getMap();
|
||||
public Bindings getBindings();
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testReturnsScriptObjectMirror() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("TestScriptObjectMirrorClass", TestScriptObjectMirror.class);
|
||||
final TestScriptObjectMirror tsom = (TestScriptObjectMirror)e.eval(
|
||||
"new TestScriptObjectMirrorClass.static({\n" +
|
||||
" getJSObject: function() { return { 'kind': 'JSObject' } },\n" +
|
||||
" getScriptObjectMirror: function() { return { 'kind': 'ScriptObjectMirror' } },\n" +
|
||||
" getMap: function() { return { 'kind': 'Map' } },\n" +
|
||||
" getBindings: function() { return { 'kind': 'Bindings' } } })\n");
|
||||
Assert.assertEquals(tsom.getJSObject().getMember("kind"), "JSObject");
|
||||
Assert.assertEquals(tsom.getScriptObjectMirror().getMember("kind"), "ScriptObjectMirror");
|
||||
Assert.assertEquals(tsom.getMap().get("kind"), "Map");
|
||||
Assert.assertEquals(tsom.getBindings().get("kind"), "Bindings");
|
||||
}
|
||||
|
||||
public interface TestListAdapter {
|
||||
public List<Object> getList();
|
||||
public Collection<Object> getCollection();
|
||||
public Queue<Object> getQueue();
|
||||
public Deque<Object> getDequeue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testReturnsListAdapter() throws ScriptException {
|
||||
final ScriptEngine e = createEngine();
|
||||
e.put("TestListAdapterClass", TestListAdapter.class);
|
||||
final TestListAdapter tla = (TestListAdapter)e.eval(
|
||||
"new TestListAdapterClass.static({\n" +
|
||||
" getList: function() { return [ 'List' ] },\n" +
|
||||
" getCollection: function() { return [ 'Collection' ] },\n" +
|
||||
" getQueue: function() { return [ 'Queue' ] },\n" +
|
||||
" getDequeue: function() { return [ 'Dequeue' ] } })\n");
|
||||
Assert.assertEquals(tla.getList().get(0), "List");
|
||||
Assert.assertEquals(tla.getCollection().iterator().next(), "Collection");
|
||||
Assert.assertEquals(tla.getQueue().peek(), "Queue");
|
||||
Assert.assertEquals(tla.getDequeue().peek(), "Dequeue");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user