/* * Given a Java class, fill in the signature structure that describes the class. * If an error occurs, JS_FALSE is returned and the error reporter called. */ static JSBool compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature) { jclass java_class = signature->java_class; if (is_java_array_class(jEnv, java_class)) { jclass component_class; signature->type = JAVA_SIGNATURE_ARRAY; component_class = get_java_array_component_class(cx, jEnv, java_class); if (!component_class) return JS_FALSE; signature->array_component_signature = jsj_GetJavaClassDescriptor(cx, jEnv, component_class); if (!signature->array_component_signature) { (*jEnv)->DeleteLocalRef(jEnv, component_class); return JS_FALSE; } } else { signature->type = get_signature_type(cx, signature); } return JS_TRUE; }
/* Get the JavaClassDescriptor that corresponds to java.lang.Object */ JavaClassDescriptor * jsj_get_jlObject_descriptor(JSContext *cx, JNIEnv *jEnv) { /* The JavaClassDescriptor for java.lang.Object */ static JavaClassDescriptor *jlObject_descriptor = NULL; if (!jlObject_descriptor) jlObject_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, jlObject); return jlObject_descriptor; }
JavaClass_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSObject *obj_arg, *JavaClass_obj; JavaObjectWrapper *java_wrapper; JavaClassDescriptor *class_descriptor; JNIEnv *jEnv; JSJavaThreadState *jsj_env; if (argc != 1 || !JSVAL_IS_OBJECT(argv[0]) || !(obj_arg = JSVAL_TO_OBJECT(argv[0])) || !JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) || ((java_wrapper = JS_GetPrivate(cx, obj_arg)) == NULL)) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_NEED_JCLASS_ARG); return JS_FALSE; } jsj_env = jsj_EnterJava(cx, &jEnv); if (!jEnv) return JS_FALSE; class_descriptor = java_wrapper->class_descriptor; if (!(*jEnv)->IsSameObject(jEnv, class_descriptor->java_class, jlClass)) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_NEED_JCLASS_ARG); jsj_ExitJava(jsj_env); return JS_FALSE; } class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_wrapper->java_obj); JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor); if (!JavaClass_obj) { jsj_ExitJava(jsj_env); return JS_FALSE; } *rval = OBJECT_TO_JSVAL(JavaClass_obj); jsj_ExitJava(jsj_env); return JS_TRUE; }
/* * 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; }
JSObject * jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj, const char *simple_class_name, jclass java_class) { JavaClassDescriptor *class_descriptor; JSObject *JavaClass_obj; class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class); if (!class_descriptor) return NULL; JavaClass_obj = jsj_new_JavaClass(cx, jEnv, parent_obj, class_descriptor); if (!JavaClass_obj) return NULL; if (!JS_DefineProperty(cx, parent_obj, simple_class_name, OBJECT_TO_JSVAL(JavaClass_obj), 0, 0, JSPROP_PERMANENT|JSPROP_READONLY|JSPROP_ENUMERATE)) return NULL; return JavaClass_obj; }
/* * 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); }
/* * 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; }