Exemple #1
0
/*
 * Convert a Java object to a boolean by attempting to call the
 * booleanValue() method on a Java object to get a boolean result.
 * This usually only works on instances of java.lang.Boolean, but the code
 * is generalized to work with any Java object that supports this method.
 *
 * Returns JS_TRUE if the call was successful.
 * Returns JS_FALSE if conversion is not possible or an error occurs.
 */
extern JSBool
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
                                 JavaClassDescriptor *class_descriptor,
                                 jobject java_obj, jsval *vp)
{
    jboolean b;
    jmethodID booleanValue;
    jclass java_class;
    
    /* Null converts to false. */
    if (!java_obj) {
        *vp = JSVAL_FALSE;
        return JS_TRUE;
    }
    java_class = class_descriptor->java_class;
    booleanValue = (*jEnv)->GetMethodID(jEnv, java_class, "booleanValue", "()Z");

    /* Non-null Java object does not have a booleanValue() method, so
       it converts to true. */
    if (!booleanValue) {
        (*jEnv)->ExceptionClear(jEnv);
        *vp = JSVAL_TRUE;
        return JS_TRUE;
    }

    b = (*jEnv)->CallBooleanMethod(jEnv, java_obj, booleanValue);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "booleanValue() method failed");
        return JS_FALSE;
    }
    *vp = BOOLEAN_TO_JSVAL(b);
    return JS_TRUE;
}
Exemple #2
0
/*
 * Convert a Java object to a number by attempting to call the
 * doubleValue() method on a Java object to get a double result.
 * This usually only works on instances of java.lang.Double, but the code
 * is generalized to work with any Java object that supports this method.
 *
 * Returns JS_TRUE if the call was successful.
 * Returns JS_FALSE if conversion is not possible or an error occurs.
 */
JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
                                JavaClassDescriptor *class_descriptor,
                                jobject java_obj, jsval *vp)
{
    jdouble d;
    jmethodID doubleValue;
    jclass java_class;

    java_class = class_descriptor->java_class;
    doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
    if (!doubleValue) {
        /* There is no doubleValue() method for the object.  Try toString()
           instead and the JS engine will attempt to convert the result to
           a number. */
        (*jEnv)->ExceptionClear(jEnv);
        return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
                                               java_obj, vp);
    }

    d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "doubleValue() method failed");
        return JS_FALSE;
    }
    return JS_NewDoubleValue(cx, d, vp);
}
Exemple #3
0
JSBool
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp)
{
    const jschar *ucs2;
    JSString *jsstr;
    jsize ucs2_len;
    jsval val;
    
    ucs2 = (*jEnv)->GetStringChars(jEnv, jstr, 0);
    if (!ucs2) {
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain Unicode characters"
                                "from Java string");
        return JS_FALSE;
    }
    
    ucs2_len = (*jEnv)->GetStringLength(jEnv, jstr);
    jsstr = JS_InternUCStringN(cx, ucs2, ucs2_len);
    (*jEnv)->ReleaseStringChars(jEnv, jstr, ucs2);
    if (!jsstr)
        return JS_FALSE;

    val = STRING_TO_JSVAL(jsstr);
    JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp);
    return JS_TRUE;
}
Exemple #4
0
/*
 * Given a JVM handle to a java.lang.Class object, malloc a C-string
 * containing the UTF8 encoding of the fully qualified name of the class.
 * It's the caller's responsibility to free the returned string.
 *
 * If an error occurs, NULL is returned and the error reporter called.
 */
const char *
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
    jstring java_class_name_jstr;
    const char *java_class_name;

    /* Get java.lang.String object containing class name */
    java_class_name_jstr =
        (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);

    if (!java_class_name_jstr)
        goto error;

    /* Fix bugzilla #183092
     * It is necessary to check Exception from JPI
     * even though java_class_name_jstr != null */
#ifdef XP_UNIX
    if ((*jEnv)->ExceptionOccurred(jEnv))
        goto error;
#endif

    /* Convert to UTF8 encoding and copy */
    java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);

    (*jEnv)->DeleteLocalRef(jEnv, java_class_name_jstr);
    return java_class_name;

error:
    jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
                                      "java.lang.Class.getName()");
    return NULL;
}
Exemple #5
0
jstring
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str)
{
    jstring result;
    result = (*jEnv)->NewString(jEnv, JS_GetStringChars(js_str),
                                JS_GetStringLength(js_str));
    if (!result) {
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
                                          "of java.lang.String");
    }
    return result;
}
Exemple #6
0
jsize
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
{
    jsize array_length = (*jEnv)->GetArrayLength(jEnv, java_array);
    jthrowable java_exception = (*jEnv)->ExceptionOccurred(jEnv);
    if (java_exception) {
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain array length");
        (*jEnv)->DeleteLocalRef(jEnv, java_exception);
        return -1;
    }
    return array_length;
}
Exemple #7
0
/*
 * Return the class of a Java array's component type.  This is not the same
 * as the array's element type.  For example, the component type of an array
 * of type SomeType[][][] is SomeType[][], but its element type is SomeType.
 *
 * If an error occurs, NULL is returned and an error reported.
 */
static jclass
get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
    jclass result;
    result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
    if (!result) {
        jsj_UnexpectedJavaError(cx, jEnv,
                                "Can't get Java array component class using "
                                "java.lang.Class.getComponentType()");
        return NULL;
    }
    return result;
}
Exemple #8
0
/*
 * Convert a Java object to a number by attempting to call the
 * doubleValue() method on a Java object to get a double result.
 * This usually only works on instances of java.lang.Double, but the code
 * is generalized to work with any Java object that supports this method.
 *
 * Returns JS_TRUE if the call was successful.
 * Returns JS_FALSE if conversion is not possible or an error occurs.
 */
JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
                                JavaClassDescriptor *class_descriptor,
                                jobject java_obj, jsval *vp)
{
    jdouble d;
    jmethodID doubleValue;
    jclass java_class;

    java_class = class_descriptor->java_class;
    doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
    if (!doubleValue) {
        /* There is no doubleValue() method for the object.  Try toString()
           instead and the JS engine will attempt to convert the result to
           a number. */
        (*jEnv)->ExceptionClear(jEnv);
        return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
                                               java_obj, vp);
    }
    /*
     * Sun Java-Plugin team work around bug to be fixed in JRE1.5, where GetMethodID 
     * called with a non-existent method name returns a non-null result.
     * See Mozilla bug 201164.
     */
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "No doubleValue() method for class %s!",
            class_descriptor->name);
        return JS_FALSE;
    }
    
    d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "doubleValue() method failed");
        return JS_FALSE;
    }
    return JS_NewDoubleValue(cx, d, vp);
}
Exemple #9
0
/*
 * Return a UTF8, null-terminated encoding of a Java string.  The string must
 * be free'ed by the caller.
 *
 * If an error occurs, returns NULL and calls the JS error reporter.
 */
const char *
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr)
{
    const char *str, *retval;

    str = (*jEnv)->GetStringUTFChars(jEnv, jstr, 0);
    if (!str) {
        jsj_UnexpectedJavaError(cx, jEnv, "Can't get UTF8 characters from "
                                          "Java string");
        return NULL;
    }
    retval = JS_strdup(cx, str);
    (*jEnv)->ReleaseStringUTFChars(jEnv, jstr, str);
    return retval;
}
Exemple #10
0
/*
 * Attempt to obtain a JS string representation of a Java object.
 * The java_obj argument must be of type java.lang.Object or a subclass.
 * If java_obj is a Java string, it's value is simply extracted and
 * copied into a JS string.  Otherwise, the toString() method is called
 * on java_obj.
 */
JSBool
jsj_ConvertJavaObjectToJSString(JSContext *cx,
                                JNIEnv *jEnv,
                                JavaClassDescriptor *class_descriptor,
                                jobject java_obj, jsval *vp)
{
    JSString *js_str;
    jstring java_str;
    jmethodID toString;
    jclass java_class;
    
    /* Create a Java string, unless java_obj is already a java.lang.String */
    if ((*jEnv)->IsInstanceOf(jEnv, java_obj, jlString)) {

        /* Extract Unicode from java.lang.String instance and convert to JS string */
        js_str = jsj_ConvertJavaStringToJSString(cx, jEnv, java_obj);
        if (!js_str)
            return JS_FALSE;
        *vp = STRING_TO_JSVAL(js_str);
        return JS_TRUE;
    }
    
    java_class = class_descriptor->java_class;
    toString = (*jEnv)->GetMethodID(jEnv, java_class, "toString",
        "()Ljava/lang/String;");
    if (!toString) {
        /* All Java objects have a toString method */
        jsj_UnexpectedJavaError(cx, jEnv, "No toString() method for class %s!",
            class_descriptor->name);
        return JS_FALSE;
    }
    java_str = (*jEnv)->CallObjectMethod(jEnv, java_obj, toString);
    if (!java_str) {
        jsj_ReportJavaError(cx, jEnv, "toString() method failed");
        return JS_FALSE;
    }
    
    /* Extract Unicode from java.lang.String instance and convert to JS string */
    js_str = jsj_ConvertJavaStringToJSString(cx, jEnv, java_str);
    if (!js_str) {
        (*jEnv)->DeleteLocalRef(jEnv, java_str);
        return JS_FALSE;
    }

    *vp = STRING_TO_JSVAL(js_str);
    (*jEnv)->DeleteLocalRef(jEnv, java_str);
    return JS_TRUE;
}
Exemple #11
0
/*
 * Return, as a C string, the JVM stack trace associated with a Java
 * exception, as would be printed by java.lang.Throwable.printStackTrace().
 * The caller is responsible for free'ing the returned string.
 *
 * Returns NULL if an error occurs.
 */
static const char *
get_java_stack_trace(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception)
{
    const char *backtrace;
    jstring backtrace_jstr;

    backtrace = NULL;
    if (java_exception && njJSUtil_getStackTrace) {
        backtrace_jstr = (*jEnv)->CallStaticObjectMethod(jEnv, njJSUtil,
                                                         njJSUtil_getStackTrace,
                                                         java_exception);
        if (!backtrace_jstr) {
            jsj_UnexpectedJavaError(cx, jEnv, "Unable to get exception stack trace");
            return NULL;
        }
        backtrace = jsj_DupJavaStringUTF(cx, jEnv, backtrace_jstr);
        (*jEnv)->DeleteLocalRef(jEnv, backtrace_jstr);
    }
    return backtrace;
} 
Exemple #12
0
/*
 * The caller must call DeleteLocalRef() on the returned object when no more
 * references remain.
 */
jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
{
    jobject java_wrapper_obj;
    JSObjectHandle *handle;

    /* Create a tiny stub object to act as the GC root that points to the
       JSObject from its netscape.javascript.JSObject counterpart. */
    handle = (JSObjectHandle*)JS_malloc(cx, sizeof(JSObjectHandle));
    if (!handle)
        return NULL;
    handle->js_obj = js_obj;
    handle->rt = JS_GetRuntime(cx);

    /* Create a new Java object that wraps the JavaScript object by storing its
       address in a private integer field. */
#ifndef OJI
#if JS_BYTES_PER_LONG == 8
    java_wrapper_obj =
        (*jEnv)->NewObject(jEnv, njJSObject, njJSObject_JSObject, (jlong)handle);
#else
    java_wrapper_obj =
        (*jEnv)->NewObject(jEnv, njJSObject, njJSObject_JSObject, (jint)handle);
#endif
#else
    if (JSJ_callbacks && JSJ_callbacks->get_java_wrapper != NULL) {
        java_wrapper_obj = JSJ_callbacks->get_java_wrapper(jEnv, (jint)handle);
    }
#endif /*! OJI */
    if (!java_wrapper_obj) {
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't create new instance of "
                                          "netscape.javascript.JSObject");
        goto done;
    }
 
    JS_AddNamedRoot(cx, &handle->js_obj, "&handle->js_obj");

done:
        
    return java_wrapper_obj;
}
Exemple #13
0
static JavaClassDescriptor *
new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
    JavaClassDescriptor *class_descriptor;

    class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
    if (!class_descriptor)
        return NULL;
    memset(class_descriptor, 0, sizeof(JavaClassDescriptor));

    class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
    if (!class_descriptor->name)
        goto error;

    java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
    if (!java_class) {
        jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
        goto error;
    }
    class_descriptor->java_class = java_class;

    if (!compute_java_class_signature(cx, jEnv, class_descriptor))
        goto error;

    class_descriptor->modifiers =
        (*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
    class_descriptor->ref_count = 1;

    if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
                          (void*)jEnv))
        goto error;

    return class_descriptor;

error:
    destroy_class_descriptor(cx, jEnv, class_descriptor);
    return NULL;
}
Exemple #14
0
/*
 * A utility routine to create a JavaScript Unicode string from a
 * java.lang.String (Unicode) string.
 */
JSString *
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str)
{
    JSString *js_str;
    jboolean is_copy;
    const jchar *ucs2_str;
    jsize ucs2_str_len;

    ucs2_str_len = (*jEnv)->GetStringLength(jEnv, java_str);
    ucs2_str = (*jEnv)->GetStringChars(jEnv, java_str, &is_copy);
    if (!ucs2_str) {
        jsj_UnexpectedJavaError(cx, jEnv,
                                "Unable to extract native Unicode from Java string");
        return NULL;
    }

    /* The string data passed into JS_NewUCString() is
       not copied, so make a copy of the Unicode character vector. */
    js_str = JS_NewUCStringCopyN(cx, ucs2_str, ucs2_str_len);

    (*jEnv)->ReleaseStringChars(jEnv, java_str, ucs2_str);
    return js_str;
}
Exemple #15
0
/*
 * Convert a JS value to an instance of java.lang.Object or one of its subclasses, 
 * performing any necessary type coercion.  If non-trivial coercion is required,
 * the cost value is incremented.  If the java_value pass-by-reference argument
 * is non-NULL, the resulting Java value is stored there.
 *
 * Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise
 */
JSBool
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
                               int *cost, jobject *java_value, JSBool *is_local_refp)
{
    JSString *jsstr;
    jclass target_java_class;
    
    JS_ASSERT(IS_REFERENCE_TYPE(signature->type));

    /* Initialize to default case, in which no new Java object is
       synthesized to perform the conversion and, therefore, no JNI local
       references are being held. */
    *is_local_refp = JS_FALSE;

    /* Get the Java type of the target value */
    target_java_class = signature->java_class;
    
    if (JSVAL_IS_OBJECT(v)) {
        JSObject *js_obj = JSVAL_TO_OBJECT(v);
        
        /* JS null is always assignable to a Java object */
        if (!js_obj) {
            if (java_value)
                *java_value = NULL;
            return JS_TRUE;
        }
        
        if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) ||
            JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) {
            
            /* The source value is a Java object wrapped inside a JavaScript
               object.  Unwrap the JS object and return the original Java
               object if it's class makes it assignment-compatible with the
               target class using Java's assignability rules. */
            JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj);
            jobject java_obj = java_wrapper->java_obj;
            
            if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) {
                if (java_value)
                    *java_value = java_obj;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
            
        } else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) {
            /* We're dealing with the reflection of a Java class */
            JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj);
            
            /* Check if target type is java.lang.Class class */
            if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) {
                if (java_value)
                    *java_value = java_class_descriptor->java_class;
                return JS_TRUE;
            }
            
            /* Check if target type is netscape.javascript.JSObject wrapper class */
            if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
                if (java_value && *java_value)
                    *is_local_refp = JS_TRUE;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
            
        } else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {

            if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
                return JS_FALSE;
            return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
                                                  java_value, is_local_refp);

        /* JS Arrays are converted, element by element, to Java arrays */
        } else if (JS_IsArrayObject(cx, js_obj) && (signature->type == JAVA_SIGNATURE_ARRAY)) {
            if (convert_js_array_to_java_array(cx, jEnv, js_obj, signature, java_value)) {
                if (java_value && *java_value)
                    *is_local_refp = JS_TRUE;
                return JS_TRUE;
            }
            return JS_FALSE;

        } else {
            /* Otherwise, see if the target type is the  netscape.javascript.JSObject
               wrapper class or one of its subclasses, in which case a
               reference is passed to the original JS object by wrapping it
               inside an instance of netscape.javascript.JSObject */
            if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value))             {
                if (java_value && *java_value)
                    *is_local_refp = JS_TRUE;
                return JS_TRUE;
            }
            
            /* Fall through, to attempt conversion to a Java string */
        }
        
    } else if (JSVAL_IS_NUMBER(v)) {
        /* JS numbers, integral or not, can be converted to instances of java.lang.Double */
        if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) {
            if (java_value) {
                jsdouble d;
                if (!JS_ValueToNumber(cx, v, &d))
                    goto conversion_error;
                *java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    jsj_UnexpectedJavaError(cx, jEnv,
                        "Couldn't construct instance of java.lang.Double");
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
        /* Fall through, to attempt conversion to a java.lang.String ... */
        
    } else if (JSVAL_IS_BOOLEAN(v)) {
        /* JS boolean values can be converted to instances of java.lang.Boolean */
        if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) {
            if (java_value) {
                JSBool b;
                if (!JS_ValueToBoolean(cx, v, &b))
                    goto conversion_error;
                *java_value =
                    (*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance " 
                        "of java.lang.Boolean");
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
        /* Fall through, to attempt conversion to a java.lang.String ... */
    }
    
    /* If the source JS type is either a string or undefined, or if no conversion
       is possible from a number, boolean or JS object, see if the target type is
       java.lang.String */
    if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
        
        /* Convert to JS string, if necessary, and then to a Java Unicode string */
        jsstr = JS_ValueToString(cx, v);
        if (jsstr) {
            if (java_value) {
                *java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
                if (*java_value) {
                    *is_local_refp = JS_TRUE;
                } else {
                    return JS_FALSE;
                }
            }

            return JS_TRUE;
        }
    }
    
conversion_error:
    return JS_FALSE;
}
Exemple #16
0
/*
 * This function is called up returning from Java back into JS as a result of
 * a thrown netscape.javascript.JSException, which itself must have been caused
 * by a JS error when Java called into JS.  The original JS error is
 * reconstituted from the JSException and re-reported as a JS error.
 *
 * Returns JS_FALSE if an internal error occurs, JS_TRUE otherwise.
 */
JSBool
jsj_ReportUncaughtJSException(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception)
{
    JSBool success;
    JSErrorReport report;
    const char *linebuf, *filename, *message, *tokenptr;
    jint lineno, token_index;
    jstring linebuf_jstr, filename_jstr, message_jstr;

    /* Initialize everything to NULL */
    memset(&report, 0, sizeof(JSErrorReport));
    success = JS_FALSE;
    filename_jstr = linebuf_jstr = message_jstr = NULL;
    filename = message = linebuf = tokenptr = NULL;

    lineno = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_lineno);
    report.lineno = lineno;

    filename_jstr = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_filename);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "Unable to access filename field of a JSException");
        goto done;
    }
    if (filename_jstr)
        filename = (*jEnv)->GetStringUTFChars(jEnv, filename_jstr, 0);
    report.filename = filename;

    linebuf_jstr = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_source);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "Unable to access source field of a JSException");
        goto done;
    }
    if (linebuf_jstr)
        linebuf = (*jEnv)->GetStringUTFChars(jEnv, linebuf_jstr, 0);
    report.linebuf = linebuf;

    token_index = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_lineno);
    report.tokenptr = linebuf + token_index;

    message_jstr = (*jEnv)->CallObjectMethod(jEnv, java_exception, jlThrowable_getMessage);
    if ((*jEnv)->ExceptionOccurred(jEnv)) {
        jsj_UnexpectedJavaError(cx, jEnv, "Unable to access message of a JSException");
        goto done;
    }
    if (message_jstr)
        message = (*jEnv)->GetStringUTFChars(jEnv, message_jstr, 0);

    js_ReportErrorAgain(cx, message, &report);

    success = JS_TRUE;

done:

    if (filename_jstr && filename)
        (*jEnv)->ReleaseStringUTFChars(jEnv, filename_jstr, filename);
    if (linebuf_jstr && linebuf)
        (*jEnv)->ReleaseStringUTFChars(jEnv, linebuf_jstr, linebuf);
    if (message_jstr && message)
        (*jEnv)->ReleaseStringUTFChars(jEnv, message_jstr, message);
    return success;
}
Exemple #17
0
/*
 * This is called upon returning from JS back into Java.  Any JS errors
 * reported during that time will be converted into Java exceptions.  It's
 * possible that a JS error was actually triggered by Java at some point, in
 * which case the original Java exception is thrown.
 */
static void
throw_any_pending_js_error_as_a_java_exception(JSJavaThreadState *jsj_env)
{
    CapturedJSError *error;
    JNIEnv *jEnv;
    jstring message_jstr, linebuf_jstr, filename_jstr;
    jint index, lineno;
    JSErrorReport *report;
    JSContext *cx;
    jsval pending_exception; 
    jobject java_obj;
    int dummy_cost;
    JSBool is_local_refp;
    JSType primitive_type;
    jthrowable java_exception;

    message_jstr = linebuf_jstr = filename_jstr = java_exception = NULL;

    /* Get the Java JNI environment */
    jEnv = jsj_env->jEnv;

    cx = jsj_env->cx;
    /* Get the pending JS exception if it exists */
    if (cx&&JS_IsExceptionPending(cx)) {
        if (!JS_GetPendingException(cx, &pending_exception))
            goto out_of_memory;

        /* Find out the JSTYPE of this jsval. */
        primitive_type = JS_TypeOfValue(cx, pending_exception);
        
        /* Convert jsval exception to a java object and then use it to
           create an instance of JSException. */ 
        if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, 
                                            pending_exception, 
                                            jsj_get_jlObject_descriptor(cx, jEnv),
                                            &dummy_cost, &java_obj, 
                                            &is_local_refp))
            goto done;
        
        java_exception = (*jEnv)->NewObject(jEnv, njJSException, 
                                            njJSException_JSException_wrap,
                                            primitive_type, java_obj);
        if (is_local_refp)
            (*jEnv)->DeleteLocalRef(jEnv, java_obj);
        if (!java_exception) 
            goto out_of_memory;
        
        /* Throw the newly-created JSException */
        if ((*jEnv)->Throw(jEnv, java_exception) < 0) {
            JS_ASSERT(0);
            jsj_LogError("Couldn't throw JSException\n");
            goto done;
        }    
        JS_ClearPendingException(cx);
        return;
    }
    if (!jsj_env->pending_js_errors) {
#ifdef DEBUG
        /* Any exception should be cleared as soon as it's detected, so there
           shouldn't be any pending. */
        if ((*jEnv)->ExceptionOccurred(jEnv)) {
            /* A Java exception occurred, but nobody in JS-land noticed. */
            JS_ASSERT(0);
            (*jEnv)->ExceptionClear(jEnv);
        }
#endif
        return;
    }

    /* Get the deepest (oldest) saved JS error */
    /* XXX - What's the right thing to do about newer errors ?
       For now we just throw them away */
    error = jsj_env->pending_js_errors;
    while (error->next)
        error = error->next;
    
    /*
     * If the JS error was originally the result of a Java exception, rethrow
     * the original exception.
     */
    if (error->java_exception) {
        (*jEnv)->Throw(jEnv, error->java_exception);
        goto done;
    }

    /* Propagate any JS errors that did not originate as Java exceptions into
       Java as an instance of netscape.javascript.JSException */

    /* First, marshall the arguments to the JSException constructor */
    message_jstr = NULL;
    if (error->message) {
        message_jstr = (*jEnv)->NewStringUTF(jEnv, error->message);
        if (!message_jstr)
            goto out_of_memory;
    }

    report = &error->report;

    filename_jstr = NULL;
    if (report->filename) {
        filename_jstr = (*jEnv)->NewStringUTF(jEnv, report->filename);
        if (!filename_jstr)
            goto out_of_memory;
    }

    linebuf_jstr = NULL;
    if (report->linebuf) {
        linebuf_jstr = (*jEnv)->NewStringUTF(jEnv, report->linebuf);
        if (!linebuf_jstr)
            goto out_of_memory;
    }

    lineno = report->lineno;
    index = report->linebuf ? report->tokenptr - report->linebuf : 0;

    /* Call the JSException constructor */
    java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException,
                                        message_jstr, filename_jstr, lineno, linebuf_jstr, index);
    if (!java_exception)
        goto out_of_memory;

    /* Throw the newly-created JSException */
    if ((*jEnv)->Throw(jEnv, java_exception) < 0) {
        JS_ASSERT(0);
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't throw JSException\n");
    }
    goto done;

out_of_memory:
    /* No recovery possible */
    JS_ASSERT(0);
    jsj_LogError("Out of memory while attempting to throw JSException\n");

done:
    jsj_ClearPendingJSErrors(jsj_env);
    /*
     * Release local references to Java objects, since some JVMs seem reticent
     * about collecting them otherwise.
     */
    if (message_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, message_jstr);
    if (filename_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, filename_jstr);
    if (linebuf_jstr)
        (*jEnv)->DeleteLocalRef(jEnv, linebuf_jstr);
    if (java_exception)
        (*jEnv)->DeleteLocalRef(jEnv, java_exception);
}
Exemple #18
0
/*
 * Add a JavaMemberDescriptor to the collection of members in class_descriptor
 * for every public field of the identified Java class.  (A separate collection
 * is kept in class_descriptor for static and instance members.)
 * If reflect_only_static_fields is set, instance fields are not reflected.  If
 * it isn't set, only instance fields are reflected and static fields are not
 * reflected.
 *
 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
 */
JSBool
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
                      JSBool reflect_only_static_fields)
{
    int i;
    JSBool ok;
    jint modifiers;
    jobject java_field;
    jstring field_name_jstr;
    jarray joFieldArray;
    jsize num_fields;
    jclass java_class;

    /* Get a java array of java.lang.reflect.Field objects, by calling
       java.lang.Class.getFields(). */
    java_class = class_descriptor->java_class;
    joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
    if (!joFieldArray) {
        jsj_UnexpectedJavaError(cx, jEnv,
                                "Can't determine Java object's fields "
                                "using java.lang.Class.getFields()");
        return JS_FALSE;
    }

    /* Iterate over the class fields */
    num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
    for (i = 0; i < num_fields; i++) {

        /* Get the i'th reflected field */
        java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
        if (!java_field) {
            jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
            return JS_FALSE;
        }

        /* Get the field modifiers, e.g. static, public, private, etc. */
        modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
        if ((*jEnv)->ExceptionOccurred(jEnv)) {
            jsj_UnexpectedJavaError(cx, jEnv,
                                    "Can't access a Field's modifiers using"
                                    "java.lang.reflect.Field.getModifiers()");
            return JS_FALSE;
        }

        /* Don't allow access to private or protected Java fields. */
        if (!(modifiers & ACC_PUBLIC))
            goto no_reflect;

        /* Reflect all instance fields or all static fields, but not both */
        if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
            goto no_reflect;

        /* Determine the unqualified name of the field */
        field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
        if (!field_name_jstr) {
            jsj_UnexpectedJavaError(cx, jEnv,
                                    "Can't obtain a Field's name"
                                    "java.lang.reflect.Field.getName()");
            return JS_FALSE;
        }

        /* Add a JavaFieldSpec object to the JavaClassDescriptor */
        ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
                                                java_field, modifiers);
        if (!ok)
            return JS_FALSE;

        (*jEnv)->DeleteLocalRef(jEnv, field_name_jstr);
        field_name_jstr = NULL;

no_reflect:
        (*jEnv)->DeleteLocalRef(jEnv, java_field);
        java_field = NULL;
    }

    (*jEnv)->DeleteLocalRef(jEnv, joFieldArray);

    /* Success */
    return JS_TRUE;
}
Exemple #19
0
jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
{
    jobject java_wrapper_obj;
    JSHashEntry *he, **hep;

    java_wrapper_obj = NULL;

#ifdef JSJ_THREADSAFE
    PR_EnterMonitor(js_obj_reflections_monitor);
#endif

    /* First, look in the hash table for an existing reflection of the same
       JavaScript object.  If one is found, return it. */
    hep = JS_HashTableRawLookup(js_obj_reflections, (JSHashNumber)js_obj, js_obj);

    /* If the same JSObject is reflected into Java more than once then we should
       return the same Java object, both for efficiency and so that the '=='
       operator works as expected in Java when comparing two JSObjects.
       However, it is not possible to hold a reference to a Java object without
       inhibiting GC of that object, at least not in a portable way, i.e.
       a weak reference. So, for now, JSObject identity is broken. */

    he = *hep;
    if (he) {
        java_wrapper_obj = (jobject)he->value;
        JS_ASSERT(java_wrapper_obj);
        if (java_wrapper_obj)
            goto done;
    }

    /* No existing reflection found, so create a new Java object that wraps
       the JavaScript object by storing its address in a private integer field. */
#ifndef OJI
    java_wrapper_obj =
        (*jEnv)->NewObject(jEnv, njJSObject, njJSObject_JSObject, (jint)js_obj);
#else
    if (JSJ_callbacks && JSJ_callbacks->get_java_wrapper != NULL) {
        java_wrapper_obj = JSJ_callbacks->get_java_wrapper(jEnv, (jint)handle);
    }
#endif /*! OJI */

    if (!java_wrapper_obj) {
        jsj_UnexpectedJavaError(cx, jEnv, "Couldn't create new instance of "
                                          "netscape.javascript.JSObject");
        goto done;
    }

    /* Add the new reflection to the hash table. */
    he = JS_HashTableRawAdd(js_obj_reflections, hep, (JSHashNumber)js_obj,
                            js_obj, java_wrapper_obj);
    if (he) {
        /* Tell the JavaScript GC about this object since the only reference
           to it may be in Java-land. */
        JS_AddNamedRoot(cx, (void*)&he->key, "&he->key");
    } else {
        JS_ReportOutOfMemory(cx);
        /* No need to delete java_wrapper_obj because Java GC will reclaim it */
        java_wrapper_obj = NULL;
    }
    
    /*
     * Release local reference to wrapper object, since some JVMs seem reticent
     * about collecting it otherwise.
     */
    /* FIXME -- beard: this seems to make calls into Java with JSObject's fail. */
    /* We should really be creating a global ref if we are putting it in a hash table. */
    /* (*jEnv)->DeleteLocalRef(jEnv, java_wrapper_obj); */

done:
#ifdef JSJ_THREADSAFE
        PR_ExitMonitor(js_obj_reflections_monitor);
#endif
        
    return java_wrapper_obj;
}
Exemple #20
0
/*
 * Add a single field, described by java_field, to the JavaMemberDescriptor
 * named by field_name within the given JavaClassDescriptor.
 *
 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
 */
static JSBool
add_java_field_to_class_descriptor(JSContext *cx,
                                   JNIEnv *jEnv,
                                   JavaClassDescriptor *class_descriptor,
                                   jstring field_name_jstr,
                                   jobject java_field,  /* a java.lang.reflect.Field */
                                   jint modifiers)
{
    jclass fieldType;
    jfieldID fieldID;
    jclass java_class;

    JSBool is_static_field;
    JavaMemberDescriptor *member_descriptor = NULL;
    const char *sig_cstr = NULL;
    const char *field_name = NULL;
    JavaSignature *signature = NULL;
    JavaFieldSpec *field_spec = NULL;

    is_static_field = modifiers & ACC_STATIC;
    if (is_static_field) {
        member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
    } else {
        member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
    }
    if (!member_descriptor)
        goto error;

    field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
    if (!field_spec)
        goto error;

    field_spec->modifiers = modifiers;

    /* Get the Java class corresponding to the type of the field */
    fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
    if (!fieldType) {
        jsj_UnexpectedJavaError(cx, jEnv,
                                "Unable to determine type of field using"
                                " java.lang.reflect.Field.getType()");
        goto error;
    }

    signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
    (*jEnv)->DeleteLocalRef(jEnv, fieldType);
    if (!signature)
        goto error;
    field_spec->signature = signature;

    field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
    if (!field_name)
        goto error;
    field_spec->name = field_name;

    /* Compute the JNI-style (string-based) signature of the field type */
    sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
    if (!sig_cstr)
        goto error;

    /* Compute the JNI fieldID and cache it for quick field access */
    java_class = class_descriptor->java_class;
    if (is_static_field)
        fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
    else
        fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
    if (!fieldID) {
        jsj_UnexpectedJavaError(cx, jEnv,
                                "Can't get Java field ID for class %s, field %s (sig=%s)",
                                class_descriptor->name, field_name, sig_cstr);
        goto error;
    }
    field_spec->fieldID = fieldID;

    JS_free(cx, (char*)sig_cstr);

    member_descriptor->field = field_spec;

    /* Success */
    return JS_TRUE;

error:
    if (field_spec) {
        JS_FREE_IF(cx, (char*)field_spec->name);
        JS_free(cx, field_spec);
    }
    JS_FREE_IF(cx, (char*)sig_cstr);
    if (signature)
        jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
    return JS_FALSE;
}