/* * 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); }
/* * Reflect a Java object into a JS value. The source object, java_obj, must * be of type java.lang.Object or a subclass and may, therefore, be an array. */ JSBool jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jsval *vp) { JavaClassDescriptor *class_descriptor; jclass java_class; JSBool ret; /* A null in Java-land is also null in JS */ if (!java_obj) { *vp = JSVAL_NULL; return JS_TRUE; } java_class = (*jEnv)->GetObjectClass(jEnv, java_obj); class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class); if (!class_descriptor) return JS_FALSE; switch (class_descriptor->type) { case JAVA_SIGNATURE_JAVA_LANG_BOOLEAN: ret = jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp); break; case JAVA_SIGNATURE_JAVA_LANG_DOUBLE: ret = jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp); break; case JAVA_SIGNATURE_JAVA_LANG_STRING: ret = jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp); break; default: ret = convert_javaobject_to_jsobject(cx, jEnv, class_descriptor, java_obj, vp); break; } (*jEnv)->DeleteLocalRef(jEnv, java_class); jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor); return ret; }
/* * 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); }
/* * This is a wrapper around JS_ReportError(), useful when an error condition * is the result of a JVM failure or exception condition. It appends the * message associated with the pending Java exception to the passed in * printf-style format string and arguments. */ static void vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap) { jobject java_obj; jclass java_class; JavaClassDescriptor *class_descriptor; jthrowable java_exception; JSType wrapped_exception_type; jsval js_exception; java_obj = NULL; class_descriptor = NULL; /* Get the exception out of the java environment. */ java_exception = (*jEnv)->ExceptionOccurred(jEnv); if (!java_exception) { JSString *err_jsstr; char *err = JS_vsmprintf(format, ap); if (!err) return; err_jsstr = JS_NewString(cx, err, strlen(err)); if (!err_jsstr) return; JS_SetPendingException(cx, STRING_TO_JSVAL(err_jsstr)); return; } (*jEnv)->ExceptionClear(jEnv); /* Check for JSException */ if (njJSException && (*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) { wrapped_exception_type = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_wrappedExceptionType); /* (int) to suppress warning */ if ((int)wrapped_exception_type != JSTYPE_EMPTY) { java_obj = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_wrappedException); if ((java_obj == NULL) && (wrapped_exception_type == JSTYPE_OBJECT)) { js_exception = JSVAL_NULL; } else { java_class = (*jEnv)->GetObjectClass(jEnv, java_obj); class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class); /* OK to delete ref, since above call adds global ref */ (*jEnv)->DeleteLocalRef(jEnv, java_class); /* Convert native JS values back to native types. */ switch(wrapped_exception_type) { case JSTYPE_NUMBER: if (!jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_BOOLEAN: if (!jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_STRING: if (!jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_VOID: js_exception = JSVAL_VOID; break; case JSTYPE_OBJECT: case JSTYPE_FUNCTION: default: if ((*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) { js_exception = OBJECT_TO_JSVAL(jsj_UnwrapJSObjectWrapper(jEnv, java_obj)); if (!js_exception) goto error; } else { if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_exception)) goto error; } } } } /* Check for internal exception */ } else { if (!JSJ_ConvertJavaObjectToJSValue(cx, java_exception, &js_exception)) { goto error; } } /* Set pending JS exception and clear the java exception. */ JS_SetPendingException(cx, js_exception); goto done; error: JS_ASSERT(0); jsj_LogError("Out of memory while attempting to throw JSException\n"); done: if (class_descriptor) jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor); if (java_obj) (*jEnv)->DeleteLocalRef(jEnv, java_obj); if (java_exception) (*jEnv)->DeleteLocalRef(jEnv, java_exception); }