@Override public void put(String name, Scriptable start, Object value) { int info = findInstanceIdInfo(name); if (info != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } int attr = (info >>> 16); if ((attr & READONLY) == 0) { if (start == this) { int id = (info & 0xFFFF); setInstanceIdValue(id, value); } else { start.put(name, start, value); } } return; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } prototypeValues.set(id, start, value); return; } } super.put(name, start, value); }
/** * @deprecated Use {@link #getTypeTag(Class)} and {@link #convertArg(Context, Scriptable, Object, * int)} for type convertion. */ public static Object convertArg(Context cx, Scriptable scope, Object arg, Class desired) { int tag = getTypeTag(desired); if (tag == JAVA_UNSUPPORTED_TYPE) { throw Context.reportRuntimeError1("msg.cant.convert", desired.getName()); } return convertArg(cx, scope, arg, tag); }
void put(Scriptable scope, String name, Object javaObject, Object value, boolean isStatic) { Map<String, Object> ht = isStatic ? staticMembers : members; Object member = ht.get(name); if (!isStatic && member == null) { // Try to get static member from instance (LC3) member = staticMembers.get(name); } if (member == null) throw reportMemberNotFound(name); if (member instanceof FieldAndMethods) { FieldAndMethods fam = (FieldAndMethods) ht.get(name); member = fam.field; } // Is this a bean property "set"? if (member instanceof BeanProperty) { BeanProperty bp = (BeanProperty) member; if (bp.setter == null) { throw reportMemberNotFound(name); } // If there's only one setter or if the value is null, use the // main setter. Otherwise, let the NativeJavaMethod decide which // setter to use: if (bp.setters == null || value == null) { Class<?> setType = bp.setter.argTypes[0]; Object[] args = {Context.jsToJava(value, setType)}; try { bp.setter.invoke(javaObject, args); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } } else { Object[] args = {value}; bp.setters.call( Context.getContext(), ScriptableObject.getTopLevelScope(scope), scope, args); } } else { if (!(member instanceof Field)) { String str = (member == null) ? "msg.java.internal.private" : "msg.java.method.assign"; throw Context.reportRuntimeError1(str, name); } Field field = (Field) member; Object javaValue = Context.jsToJava(value, field.getType()); try { field.set(javaObject, javaValue); } catch (IllegalAccessException accessEx) { if ((field.getModifiers() & Modifier.FINAL) != 0) { // treat Java final the same as JavaScript [[READONLY]] return; } throw Context.throwAsScriptRuntimeEx(accessEx); } catch (IllegalArgumentException argEx) { throw Context.reportRuntimeError3( "msg.java.internal.field.type", value.getClass().getName(), field, javaObject.getClass().getName()); } } }
public Object execIdCall( IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (f.hasTag(FTAG)) { if (f.methodId() == Id_constructor) { throw Context.reportRuntimeError1("msg.cant.call.indirect", "With"); } } throw f.unknown(); }
JavaMembers(Scriptable scope, Class<?> cl, boolean includeProtected) { try { Context cx = ContextFactory.getGlobal().enterContext(); ClassShutter shutter = cx.getClassShutter(); if (shutter != null && !shutter.visibleToScripts(cl.getName())) { throw Context.reportRuntimeError1("msg.access.prohibited", cl.getName()); } this.includePrivate = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS); this.members = new HashMap<String, Object>(); this.staticMembers = new HashMap<String, Object>(); this.cl = cl; reflect(scope, includeProtected); } finally { Context.exit(); } }
@Override public Object getDefaultValue(Class<?> hint) { if (hint == ScriptRuntime.FunctionClass) return this; Object rval; Class<?> type; try { rval = field.get(javaObject); type = field.getType(); } catch (IllegalAccessException accEx) { throw Context.reportRuntimeError1("msg.java.internal.private", field.getName()); } Context cx = Context.getContext(); rval = cx.getWrapFactory().wrap(cx, this, rval, type); if (rval instanceof Scriptable) { rval = ((Scriptable) rval).getDefaultValue(hint); } return rval; }
public Object execIdCall( IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(SCRIPT_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: { String source = (args.length == 0) ? "" : ScriptRuntime.toString(args[0]); Script script = compile(cx, source); NativeScript nscript = new NativeScript(script); ScriptRuntime.setObjectProtoAndParent(nscript, scope); return nscript; } case Id_toString: { NativeScript real = realThis(thisObj, f); Script realScript = real.script; if (realScript == null) { return ""; } return cx.decompileScript(realScript, 0); } case Id_exec: { throw Context.reportRuntimeError1("msg.cant.call.indirect", "exec"); } case Id_compile: { NativeScript real = realThis(thisObj, f); String source = ScriptRuntime.toString(args, 0); real.script = compile(cx, source); return real; } } throw new IllegalArgumentException(String.valueOf(id)); }
@Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // Find a method that matches the types given. if (methods.length == 0) { throw new RuntimeException("No methods defined for call"); } int index = findFunction(cx, methods, args); if (index < 0) { Class<?> c = methods[0].method().getDeclaringClass(); String sig = c.getName() + '.' + getFunctionName() + '(' + scriptSignature(args) + ')'; throw Context.reportRuntimeError1("msg.java.no_such_method", sig); } MemberBox meth = methods[index]; Class<?>[] argTypes = meth.argTypes; if (meth.vararg) { // marshall the explicit parameters Object[] newArgs = new Object[argTypes.length]; for (int i = 0; i < argTypes.length - 1; i++) { newArgs[i] = Context.jsToJava(args[i], argTypes[i]); } Object varArgs; // Handle special situation where a single variable parameter // is given and it is a Java or ECMA array or is null. if (args.length == argTypes.length && (args[args.length - 1] == null || args[args.length - 1] instanceof NativeArray || args[args.length - 1] instanceof NativeJavaArray)) { // convert the ECMA array into a native array varArgs = Context.jsToJava(args[args.length - 1], argTypes[argTypes.length - 1]); } else { // marshall the variable parameters Class<?> componentType = argTypes[argTypes.length - 1].getComponentType(); varArgs = Array.newInstance(componentType, args.length - argTypes.length + 1); for (int i = 0; i < Array.getLength(varArgs); i++) { Object value = Context.jsToJava(args[argTypes.length - 1 + i], componentType); Array.set(varArgs, i, value); } } // add varargs newArgs[argTypes.length - 1] = varArgs; // replace the original args with the new one args = newArgs; } else { // First, we marshall the args. Object[] origArgs = args; for (int i = 0; i < args.length; i++) { Object arg = args[i]; Object coerced = Context.jsToJava(arg, argTypes[i]); if (coerced != arg) { if (origArgs == args) { args = args.clone(); } args[i] = coerced; } } } Object javaObject; if (meth.isStatic()) { javaObject = null; // don't need an object } else { Scriptable o = thisObj; Class<?> c = meth.getDeclaringClass(); for (; ; ) { if (o == null) { throw Context.reportRuntimeError3( "msg.nonjava.method", getFunctionName(), ScriptRuntime.toString(thisObj), c.getName()); } if (o instanceof Wrapper) { javaObject = ((Wrapper) o).unwrap(); if (c.isInstance(javaObject)) { break; } } o = o.getPrototype(); } } if (debug) { printDebug("Calling ", meth, args); } Object retval = meth.invoke(javaObject, args); Class<?> staticType = meth.method().getReturnType(); if (debug) { Class<?> actualType = (retval == null) ? null : retval.getClass(); System.err.println( " ----- Returned " + retval + " actual = " + actualType + " expect = " + staticType); } Object wrapped = cx.getWrapFactory() .wrap( cx, scope, retval, staticType); if (debug) { Class<?> actualType = (wrapped == null) ? null : wrapped.getClass(); System.err.println(" ----- Wrapped as " + wrapped + " class = " + actualType); } if (wrapped == null && staticType == Void.TYPE) { wrapped = Undefined.instance; } return wrapped; }
/** * Create a JavaScript function object from a Java method. * * <p>The <code>member</code> argument must be either a java.lang.reflect.Method * or a java.lang.reflect.Constructor and must match one of two forms.<p> * * The first form is a member with zero or more parameters * of the following types: Object, String, boolean, Scriptable, * int, or double. The Long type is not supported * because the double representation of a long (which is the * EMCA-mandated storage type for Numbers) may lose precision. * If the member is a Method, the return value must be void or one * of the types allowed for parameters.<p> * * The runtime will perform appropriate conversions based * upon the type of the parameter. A parameter type of * Object specifies that no conversions are to be done. A parameter * of type String will use Context.toString to convert arguments. * Similarly, parameters of type double, boolean, and Scriptable * will cause Context.toNumber, Context.toBoolean, and * Context.toObject, respectively, to be called.<p> * * If the method is not static, the Java 'this' value will * correspond to the JavaScript 'this' value. Any attempt * to call the function with a 'this' value that is not * of the right Java type will result in an error.<p> * * The second form is the variable arguments (or "varargs") * form. If the FunctionObject will be used as a constructor, * the member must have the following parameters * <pre> * (Context cx, Object[] args, Function ctorObj, * boolean inNewExpr)</pre> * and if it is a Method, be static and return an Object result.<p> * * Otherwise, if the FunctionObject will <i>not</i> be used to define a * constructor, the member must be a static Method with parameters * (Context cx, Scriptable thisObj, Object[] args, * Function funObj) </pre> * <pre> * and an Object result.<p> * * When the function varargs form is called as part of a function call, * the <code>args</code> parameter contains the * arguments, with <code>thisObj</code> * set to the JavaScript 'this' value. <code>funObj</code> * is the function object for the invoked function.<p> * * When the constructor varargs form is called or invoked while evaluating * a <code>new</code> expression, <code>args</code> contains the * arguments, <code>ctorObj</code> refers to this FunctionObject, and * <code>inNewExpr</code> is true if and only if a <code>new</code> * expression caused the call. This supports defining a function that * has different behavior when called as a constructor than when * invoked as a normal function call. (For example, the Boolean * constructor, when called as a function, * will convert to boolean rather than creating a new object.)<p> * * @param name the name of the function * @param methodOrConstructor a java.lang.reflect.Method or a java.lang.reflect.Constructor * that defines the object * @param scope enclosing scope of function * @see gov.nbcs.rp.common.js.javascript.Scriptable */ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope) { if (methodOrConstructor instanceof Constructor) { member = new MemberBox((Constructor) methodOrConstructor); isStatic = true; // well, doesn't take a 'this' } else { member = new MemberBox((Method) methodOrConstructor); isStatic = member.isStatic(); } String methodName = member.getName(); this.functionName = name; Class[] types = member.argTypes; int arity = types.length; if ((arity == 4) && (types[1].isArray() || types[2].isArray())) { // Either variable args or an error. if (types[1].isArray()) { if (!isStatic || (types[0] != ScriptRuntime.ContextClass) || (types[1].getComponentType() != ScriptRuntime.ObjectClass) || (types[2] != ScriptRuntime.FunctionClass) || (types[3] != Boolean.TYPE)) { throw Context.reportRuntimeError1("msg.varargs.ctor", methodName); } parmsLength = VARARGS_CTOR; } else { if (!isStatic || (types[0] != ScriptRuntime.ContextClass) || (types[1] != ScriptRuntime.ScriptableClass) || (types[2].getComponentType() != ScriptRuntime.ObjectClass) || (types[3] != ScriptRuntime.FunctionClass)) { throw Context.reportRuntimeError1("msg.varargs.fun", methodName); } parmsLength = VARARGS_METHOD; } } else { parmsLength = arity; if (arity > 0) { typeTags = new byte[arity]; for (int i = 0; i != arity; ++i) { int tag = getTypeTag(types[i]); if (tag == JAVA_UNSUPPORTED_TYPE) { throw Context.reportRuntimeError2("msg.bad.parms", types[i].getName(), methodName); } typeTags[i] = (byte) tag; } } } if (member.isMethod()) { Method method = member.method(); Class returnType = method.getReturnType(); if (returnType == Void.TYPE) { hasVoidReturn = true; } else { returnTypeTag = getTypeTag(returnType); } } else { Class ctorType = member.getDeclaringClass(); if (!ScriptRuntime.ScriptableClass.isAssignableFrom(ctorType)) { throw Context.reportRuntimeError1("msg.bad.ctor.return", ctorType.getName()); } } ScriptRuntime.setFunctionProtoAndParent(this, scope); }