/** * Return new {@link Scriptable} instance using the default constructor for the class of the * underlying Java method. Return null to indicate that the call method should be used to create * new objects. */ public Scriptable createObject(Context cx, Scriptable scope) { if (member.isCtor() || (parmsLength == VARARGS_CTOR)) { return null; } Scriptable result; try { result = (Scriptable) member.getDeclaringClass().newInstance(); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } result.setPrototype(getClassPrototype()); result.setParentScope(getParentScope()); return result; }
/** * Define this function as a JavaScript constructor. * * <p>Sets up the "prototype" and "constructor" properties. Also calls setParent and setPrototype * with appropriate values. Then adds the function object as a property of the given scope, using * <code>prototype.getClassName()</code> as the name of the property. * * @param scope the scope in which to define the constructor (typically the global object) * @param prototype the prototype object * @see gov.nbcs.rp.common.js.javascript.Scriptable#setParentScope * @see gov.nbcs.rp.common.js.javascript.Scriptable#setPrototype * @see gov.nbcs.rp.common.js.javascript.Scriptable#getClassName */ public void addAsConstructor(Scriptable scope, Scriptable prototype) { ScriptRuntime.setFunctionProtoAndParent(this, scope); setImmunePrototypeProperty(prototype); prototype.setParentScope(this); final int attr = ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY; defineProperty(prototype, "constructor", this, attr); String name = prototype.getClassName(); defineProperty(scope, name, this, ScriptableObject.DONTENUM); setParentScope(scope); }
@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; }