📄 scriptableobject.java
字号:
* to define the JavaScript constructor. If the class has three * or more constructors, an {@link EvaluatorException} * will be thrown.<p> * * Finally, if there is a method * <pre> * static void finishInit(Scriptable scope, FunctionObject constructor, * Scriptable prototype)</pre> * * it will be called to finish any initialization. The <code>scope</code> * argument will be passed, along with the newly created constructor and * the newly created prototype.<p> * * @param scope The scope in which to define the constructor. * @param clazz The Java class to use to define the JavaScript objects * and properties. * @exception IllegalAccessException if access is not available * to a reflected class member * @exception InstantiationException if unable to instantiate * the named class * @exception InvocationTargetException if an exception is thrown * during execution of methods of the named class * @see org.mozilla.javascript.Function * @see org.mozilla.javascript.FunctionObject * @see org.mozilla.javascript.ScriptableObject#READONLY * @see org.mozilla.javascript.ScriptableObject#defineProperty */ public static void defineClass(Scriptable scope, Class clazz) throws IllegalAccessException, InstantiationException, InvocationTargetException { defineClass(scope, clazz, false, false); } /** * Defines JavaScript objects from a Java class, optionally * allowing sealing. * * Similar to <code>defineClass(Scriptable scope, Class clazz)</code> * except that sealing is allowed. An object that is sealed cannot have * properties added or removed. Note that sealing is not allowed in * the current ECMA/ISO language specification, but is likely for * the next version. * * @param scope The scope in which to define the constructor. * @param clazz The Java class to use to define the JavaScript objects * and properties. The class must implement Scriptable. * @param sealed Whether or not to create sealed standard objects that * cannot be modified. * @exception IllegalAccessException if access is not available * to a reflected class member * @exception InstantiationException if unable to instantiate * the named class * @exception InvocationTargetException if an exception is thrown * during execution of methods of the named class * @since 1.4R3 */ public static void defineClass(Scriptable scope, Class clazz, boolean sealed) throws IllegalAccessException, InstantiationException, InvocationTargetException { defineClass(scope, clazz, sealed, false); } /** * Defines JavaScript objects from a Java class, optionally * allowing sealing and mapping of Java inheritance to JavaScript * prototype-based inheritance. * * Similar to <code>defineClass(Scriptable scope, Class clazz)</code> * except that sealing and inheritance mapping are allowed. An object * that is sealed cannot have properties added or removed. Note that * sealing is not allowed in the current ECMA/ISO language specification, * but is likely for the next version. * * @param scope The scope in which to define the constructor. * @param clazz The Java class to use to define the JavaScript objects * and properties. The class must implement Scriptable. * @param sealed Whether or not to create sealed standard objects that * cannot be modified. * @param mapInheritance Whether or not to map Java inheritance to * JavaScript prototype-based inheritance. * @return the class name for the prototype of the specified class * @exception IllegalAccessException if access is not available * to a reflected class member * @exception InstantiationException if unable to instantiate * the named class * @exception InvocationTargetException if an exception is thrown * during execution of methods of the named class * @since 1.6R2 */ public static String defineClass(Scriptable scope, Class clazz, boolean sealed, boolean mapInheritance) throws IllegalAccessException, InstantiationException, InvocationTargetException { Method[] methods = FunctionObject.getMethodList(clazz); for (int i=0; i < methods.length; i++) { Method method = methods[i]; if (!method.getName().equals("init")) continue; Class[] parmTypes = method.getParameterTypes(); if (parmTypes.length == 3 && parmTypes[0] == ScriptRuntime.ContextClass && parmTypes[1] == ScriptRuntime.ScriptableClass && parmTypes[2] == Boolean.TYPE && Modifier.isStatic(method.getModifiers())) { Object args[] = { Context.getContext(), scope, sealed ? Boolean.TRUE : Boolean.FALSE }; method.invoke(null, args); return null; } if (parmTypes.length == 1 && parmTypes[0] == ScriptRuntime.ScriptableClass && Modifier.isStatic(method.getModifiers())) { Object args[] = { scope }; method.invoke(null, args); return null; } } // If we got here, there isn't an "init" method with the right // parameter types. Constructor[] ctors = clazz.getConstructors(); Constructor protoCtor = null; for (int i=0; i < ctors.length; i++) { if (ctors[i].getParameterTypes().length == 0) { protoCtor = ctors[i]; break; } } if (protoCtor == null) { throw Context.reportRuntimeError1( "msg.zero.arg.ctor", clazz.getName()); } Scriptable proto = (Scriptable) protoCtor.newInstance(ScriptRuntime.emptyArgs); String className = proto.getClassName(); // Set the prototype's prototype, trying to map Java inheritance to JS // prototype-based inheritance if requested to do so. Scriptable superProto = null; if (mapInheritance) { Class superClass = clazz.getSuperclass(); if (ScriptRuntime.ScriptableClass.isAssignableFrom(superClass)) { String name = ScriptableObject.defineClass(scope, superClass, sealed, mapInheritance); if (name != null) { superProto = ScriptableObject.getClassPrototype(scope, name); } } } if (superProto == null) { superProto = ScriptableObject.getObjectPrototype(scope); } proto.setPrototype(superProto); // Find out whether there are any methods that begin with // "js". If so, then only methods that begin with special // prefixes will be defined as JavaScript entities. final String functionPrefix = "jsFunction_"; final String staticFunctionPrefix = "jsStaticFunction_"; final String getterPrefix = "jsGet_"; final String setterPrefix = "jsSet_"; final String ctorName = "jsConstructor"; Member ctorMember = FunctionObject.findSingleMethod(methods, ctorName); if (ctorMember == null) { if (ctors.length == 1) { ctorMember = ctors[0]; } else if (ctors.length == 2) { if (ctors[0].getParameterTypes().length == 0) ctorMember = ctors[1]; else if (ctors[1].getParameterTypes().length == 0) ctorMember = ctors[0]; } if (ctorMember == null) { throw Context.reportRuntimeError1( "msg.ctor.multiple.parms", clazz.getName()); } } FunctionObject ctor = new FunctionObject(className, ctorMember, scope); if (ctor.isVarArgsMethod()) { throw Context.reportRuntimeError1 ("msg.varargs.ctor", ctorMember.getName()); } ctor.addAsConstructor(scope, proto); Method finishInit = null; for (int i=0; i < methods.length; i++) { if (methods[i] == ctorMember) { continue; } String name = methods[i].getName(); if (name.equals("finishInit")) { Class[] parmTypes = methods[i].getParameterTypes(); if (parmTypes.length == 3 && parmTypes[0] == ScriptRuntime.ScriptableClass && parmTypes[1] == FunctionObject.class && parmTypes[2] == ScriptRuntime.ScriptableClass && Modifier.isStatic(methods[i].getModifiers())) { finishInit = methods[i]; continue; } } // ignore any compiler generated methods. if (name.indexOf('$') != -1) continue; if (name.equals(ctorName)) continue; String prefix = null; if (name.startsWith(functionPrefix)) { prefix = functionPrefix; } else if (name.startsWith(staticFunctionPrefix)) { prefix = staticFunctionPrefix; if (!Modifier.isStatic(methods[i].getModifiers())) { throw Context.reportRuntimeError( "jsStaticFunction must be used with static method."); } } else if (name.startsWith(getterPrefix)) { prefix = getterPrefix; } else if (name.startsWith(setterPrefix)) { prefix = setterPrefix; } else { continue; } name = name.substring(prefix.length()); if (prefix == setterPrefix) continue; // deal with set when we see get if (prefix == getterPrefix) { if (!(proto instanceof ScriptableObject)) { throw Context.reportRuntimeError2( "msg.extend.scriptable", proto.getClass().toString(), name); } Method setter = FunctionObject.findSingleMethod( methods, setterPrefix + name); int attr = ScriptableObject.PERMANENT | ScriptableObject.DONTENUM | (setter != null ? 0 : ScriptableObject.READONLY); ((ScriptableObject) proto).defineProperty(name, null, methods[i], setter, attr); continue; } FunctionObject f = new FunctionObject(name, methods[i], proto); if (f.isVarArgsConstructor()) { throw Context.reportRuntimeError1 ("msg.varargs.fun", ctorMember.getName()); } Scriptable dest = prefix == staticFunctionPrefix ? ctor : proto; defineProperty(dest, name, f, DONTENUM); if (sealed) { f.sealObject(); } } // Call user code to complete initialization if necessary. if (finishInit != null) { Object[] finishArgs = { scope, ctor, proto }; finishInit.invoke(null, finishArgs); } // Seal the object if necessary. if (sealed) { ctor.sealObject(); if (proto instanceof ScriptableObject) { ((ScriptableObject) proto).sealObject(); } } return className; } /** * Define a JavaScript property. * * Creates the property with an initial value and sets its attributes. * * @param propertyName the name of the property to define. * @param value the initial value of the property * @param attributes the attributes of the JavaScript property * @see org.mozilla.javascript.Scriptable#put */ public void defineProperty(String propertyName, Object value, int attributes) { put(propertyName, this, value); setAttributes(propertyName, attributes); } /** * Utility method to add properties to arbitrary Scriptable object. * If destination is instance of ScriptableObject, calls * defineProperty there, otherwise calls put in destination * ignoring attributes */ public static void defineProperty(Scriptable destination, String propertyName, Object value, int attributes) { if (!(destination instanceof ScriptableObject)) { destination.put(propertyName, destination, value); return; } ScriptableObject so = (ScriptableObject)destination; so.defineProperty(propertyName, value, attributes); } /** * Define a JavaScript property with getter and setter side effects. * * If the setter is not found, the attribute READONLY is added to * the given attributes. <p> * * The getter must be a method with zero parameters, and the setter, if * found, must be a method with one parameter.<p> * * @param propertyName the name of the property to define. This name * also affects the name of the setter and getter * to search for. If the propertyId is "foo", then * <code>clazz</code> will be searched for "getFoo" * and "setFoo" methods. * @param clazz the Java class to search for the getter and setter * @param attributes the attributes of the JavaScript property * @see org.mozilla.javascript.Scriptable#put */ public void defineProperty(String propertyName, Class clazz, int attributes) { int length = propertyName.length(); if (length == 0) throw new IllegalArgumentException(); char[] buf = new char[3 + length]; propertyName.getChars(0, length, buf, 3); buf[3] = Character.toUpperCase(buf[3]); buf[0] = 'g'; buf[1] = 'e'; buf[2] = 't';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -