Search in sources :

Example 1 with JSGetter

use of org.mozilla.javascript.annotations.JSGetter in project hackpad by dropbox.

the class ScriptableObject method buildClassCtor.

static <T extends Scriptable> BaseFunction buildClassCtor(Scriptable scope, Class<T> 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<? super T> superClass = clazz.getSuperclass();
        if (ScriptRuntime.ScriptableClass.isAssignableFrom(superClass) && !Modifier.isAbstract(superClass.getModifiers())) {
            Class<? extends Scriptable> superScriptable = extendsScriptable(superClass);
            String name = ScriptableObject.defineClass(scope, superScriptable, 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 = findAnnotatedMember(methods, JSConstructor.class);
    if (ctorMember == null) {
        ctorMember = findAnnotatedMember(ctors, JSConstructor.class);
    }
    if (ctorMember == null) {
        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.initAsConstructor(scope, proto);
    Method finishInit = null;
    HashSet<String> staticNames = new HashSet<String>(), instanceNames = new HashSet<String>();
    for (Method method : methods) {
        if (method == ctorMember) {
            continue;
        }
        String name = method.getName();
        if (name.equals("finishInit")) {
            Class<?>[] parmTypes = method.getParameterTypes();
            if (parmTypes.length == 3 && parmTypes[0] == ScriptRuntime.ScriptableClass && parmTypes[1] == FunctionObject.class && parmTypes[2] == ScriptRuntime.ScriptableClass && Modifier.isStatic(method.getModifiers())) {
                finishInit = method;
                continue;
            }
        }
        // ignore any compiler generated methods.
        if (name.indexOf('$') != -1)
            continue;
        if (name.equals(ctorName))
            continue;
        Annotation annotation = null;
        String prefix = null;
        if (method.isAnnotationPresent(JSFunction.class)) {
            annotation = method.getAnnotation(JSFunction.class);
        } else if (method.isAnnotationPresent(JSStaticFunction.class)) {
            annotation = method.getAnnotation(JSStaticFunction.class);
        } else if (method.isAnnotationPresent(JSGetter.class)) {
            annotation = method.getAnnotation(JSGetter.class);
        } else if (method.isAnnotationPresent(JSSetter.class)) {
            continue;
        }
        if (annotation == null) {
            if (name.startsWith(functionPrefix)) {
                prefix = functionPrefix;
            } else if (name.startsWith(staticFunctionPrefix)) {
                prefix = staticFunctionPrefix;
            } else if (name.startsWith(getterPrefix)) {
                prefix = getterPrefix;
            } else if (annotation == null) {
                // we deal with that when we see the getter
                continue;
            }
        }
        boolean isStatic = annotation instanceof JSStaticFunction || prefix == staticFunctionPrefix;
        HashSet<String> names = isStatic ? staticNames : instanceNames;
        String propName = getPropertyName(name, prefix, annotation);
        if (names.contains(propName)) {
            throw Context.reportRuntimeError2("duplicate.defineClass.name", name, propName);
        }
        names.add(propName);
        name = propName;
        if (annotation instanceof JSGetter || prefix == getterPrefix) {
            if (!(proto instanceof ScriptableObject)) {
                throw Context.reportRuntimeError2("msg.extend.scriptable", proto.getClass().toString(), name);
            }
            Method setter = findSetterMethod(methods, name, setterPrefix);
            int attr = ScriptableObject.PERMANENT | ScriptableObject.DONTENUM | (setter != null ? 0 : ScriptableObject.READONLY);
            ((ScriptableObject) proto).defineProperty(name, null, method, setter, attr);
            continue;
        }
        if (isStatic && !Modifier.isStatic(method.getModifiers())) {
            throw Context.reportRuntimeError("jsStaticFunction must be used with static method.");
        }
        FunctionObject f = new FunctionObject(name, method, proto);
        if (f.isVarArgsConstructor()) {
            throw Context.reportRuntimeError1("msg.varargs.fun", ctorMember.getName());
        }
        defineProperty(isStatic ? ctor : proto, 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 ctor;
}
Also used : JSConstructor(org.mozilla.javascript.annotations.JSConstructor) JSStaticFunction(org.mozilla.javascript.annotations.JSStaticFunction) JSSetter(org.mozilla.javascript.annotations.JSSetter) JSFunction(org.mozilla.javascript.annotations.JSFunction) Member(java.lang.reflect.Member) JSGetter(org.mozilla.javascript.annotations.JSGetter) HashSet(java.util.HashSet) Constructor(java.lang.reflect.Constructor) JSConstructor(org.mozilla.javascript.annotations.JSConstructor) Method(java.lang.reflect.Method) Annotation(java.lang.annotation.Annotation) AccessibleObject(java.lang.reflect.AccessibleObject) DebuggableObject(org.mozilla.javascript.debug.DebuggableObject)

Aggregations

Annotation (java.lang.annotation.Annotation)1 AccessibleObject (java.lang.reflect.AccessibleObject)1 Constructor (java.lang.reflect.Constructor)1 Member (java.lang.reflect.Member)1 Method (java.lang.reflect.Method)1 HashSet (java.util.HashSet)1 JSConstructor (org.mozilla.javascript.annotations.JSConstructor)1 JSFunction (org.mozilla.javascript.annotations.JSFunction)1 JSGetter (org.mozilla.javascript.annotations.JSGetter)1 JSSetter (org.mozilla.javascript.annotations.JSSetter)1 JSStaticFunction (org.mozilla.javascript.annotations.JSStaticFunction)1 DebuggableObject (org.mozilla.javascript.debug.DebuggableObject)1