📄 functionobject.java
字号:
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Norris Boyd * Igor Bukanov * David C. Navas * Ted Neward * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */// API classpackage org.mozilla.javascript;import java.lang.reflect.*;import java.io.*;public class FunctionObject extends BaseFunction{ static final long serialVersionUID = -5332312783643935019L; /** * 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 org.mozilla.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); } /** * @return One of <tt>JAVA_*_TYPE</tt> constants to indicate desired type * or {@link #JAVA_UNSUPPORTED_TYPE} if the convertion is not * possible */ public static int getTypeTag(Class type) { if (type == ScriptRuntime.StringClass) return JAVA_STRING_TYPE; if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) return JAVA_INT_TYPE; if (type == ScriptRuntime.BooleanClass || type == Boolean.TYPE) return JAVA_BOOLEAN_TYPE; if (type == ScriptRuntime.DoubleClass || type == Double.TYPE) return JAVA_DOUBLE_TYPE; if (ScriptRuntime.ScriptableClass.isAssignableFrom(type)) return JAVA_SCRIPTABLE_TYPE; if (type == ScriptRuntime.ObjectClass) return JAVA_OBJECT_TYPE; // Note that the long type is not supported; see the javadoc for // the constructor for this class return JAVA_UNSUPPORTED_TYPE; } public static Object convertArg(Context cx, Scriptable scope, Object arg, int typeTag) { switch (typeTag) { case JAVA_STRING_TYPE: if (arg instanceof String) return arg; return ScriptRuntime.toString(arg); case JAVA_INT_TYPE: if (arg instanceof Integer) return arg; return new Integer(ScriptRuntime.toInt32(arg)); case JAVA_BOOLEAN_TYPE: if (arg instanceof Boolean) return arg; return ScriptRuntime.toBoolean(arg) ? Boolean.TRUE : Boolean.FALSE; case JAVA_DOUBLE_TYPE: if (arg instanceof Double) return arg; return new Double(ScriptRuntime.toNumber(arg)); case JAVA_SCRIPTABLE_TYPE: if (arg instanceof Scriptable) return arg; return ScriptRuntime.toObject(cx, scope, arg); case JAVA_OBJECT_TYPE: return arg; default: throw new IllegalArgumentException(); } } /** * Return the value defined by the method used to construct the object * (number of parameters of the method, or 1 if the method is a "varargs" * form). */ public int getArity() { return parmsLength < 0 ? 1 : parmsLength; } /** * Return the same value as {@link #getArity()}. */ public int getLength() { return getArity(); } public String getFunctionName() { return (functionName == null) ? "" : functionName; } /** * Get Java method or constructor this function represent. */ public Member getMethodOrConstructor() { if (member.isMethod()) { return member.method(); } else { return member.ctor(); } } static Method findSingleMethod(Method[] methods, String name) { Method found = null; for (int i = 0, N = methods.length; i != N; ++i) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -