📄 jsj_javaobject.c
字号:
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp){ JavaObjectWrapper *java_wrapper; JavaClassDescriptor *class_descriptor; jobject java_obj; JNIEnv *jEnv; JSJavaThreadState *jsj_env; JSBool result; java_wrapper = JS_GetPrivate(cx, obj); if (!java_wrapper) { if (type == JSTYPE_OBJECT) { *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_OP_JOBJECT); return JS_FALSE; } java_obj = java_wrapper->java_obj; class_descriptor = java_wrapper->class_descriptor; switch (type) { case JSTYPE_OBJECT: *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; case JSTYPE_FUNCTION: JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_CONVERT_TO_FUNC); return JS_FALSE; case JSTYPE_VOID: case JSTYPE_STRING: /* Get the Java per-thread environment pointer for this JSContext */ jsj_env = jsj_EnterJava(cx, &jEnv); if (!jEnv) return JS_FALSE; /* Either extract a C-string from the java.lang.String object or call the Java toString() method */ result = jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp); jsj_ExitJava(jsj_env); return result; case JSTYPE_NUMBER: /* Get the Java per-thread environment pointer for this JSContext */ jsj_env = jsj_EnterJava(cx, &jEnv); if (!jEnv) return JS_FALSE; /* Call Java doubleValue() method, if applicable */ result = jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp); jsj_ExitJava(jsj_env); return result; case JSTYPE_BOOLEAN: /* Get the Java per-thread environment pointer for this JSContext */ jsj_env = jsj_EnterJava(cx, &jEnv); if (!jEnv) return JS_FALSE; /* Call booleanValue() method, if applicable */ result = jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp); jsj_ExitJava(jsj_env); return result; default: JS_ASSERT(0); return JS_FALSE; }}/* * Get a property from the prototype object of a native ECMA object, i.e. * return <js_constructor_name>.prototype.<member_name> * This is used to allow Java objects to inherit methods from Array.prototype * and String.prototype. */static JSBoolinherit_props_from_JS_natives(JSContext *cx, const char *js_constructor_name, const char *member_name, jsval *vp){ JSObject *global_obj, *constructor_obj, *prototype_obj; jsval constructor_val, prototype_val; global_obj = JS_GetGlobalObject(cx); JS_ASSERT(global_obj); if (!global_obj) return JS_FALSE; JS_GetProperty(cx, global_obj, js_constructor_name, &constructor_val); JS_ASSERT(JSVAL_IS_OBJECT(constructor_val)); constructor_obj = JSVAL_TO_OBJECT(constructor_val); JS_GetProperty(cx, constructor_obj, "prototype", &prototype_val); JS_ASSERT(JSVAL_IS_OBJECT(prototype_val)); prototype_obj = JSVAL_TO_OBJECT(prototype_val); return JS_GetProperty(cx, prototype_obj, member_name, vp) && *vp != JSVAL_VOID;}struct JSJPropertyInfo { JSBool wantProp; /* input param tells whether prop is returned */ const char* name; /* output param, name of property (XXX ASCII) */ uintN attributes; /* output param, attributes of property */ JSProperty *prop; /* output param, if wantProp, held pointer that must be released via OBJ_DROP_PROPERTY */};typedef struct JSJPropertyInfo JSJPropertyInfo;static JSBoollookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj, JavaObjectWrapper **java_wrapperp, jsid id, JavaMemberDescriptor **member_descriptorp, jsval *vp, JSObject **proto_chainp, JSJPropertyInfo *prop_infop){ jsval idval; JavaObjectWrapper *java_wrapper; JavaMemberDescriptor *member_descriptor; const char *member_name; JavaClassDescriptor *class_descriptor; JSObject *proto_chain; JSBool found_in_proto; found_in_proto = JS_FALSE; member_descriptor = NULL; java_wrapper = JS_GetPrivate(cx, obj); /* Handle accesses to prototype object */ if (!java_wrapper) { if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) && (member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) { if (!strcmp(member_name, "constructor")) goto done; } JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_OP_JOBJECT); return JS_FALSE; } class_descriptor = java_wrapper->class_descriptor; JS_ASSERT(IS_REFERENCE_TYPE(class_descriptor->type)); member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id); if (member_descriptor) goto done; /* Instances can reference static methods and fields */ member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id); if (member_descriptor) goto done; /* Ensure that the property we're searching for is string-valued. */ JS_IdToValue(cx, id, &idval); if (!JSVAL_IS_STRING(idval)) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_JOBJECT_EXPR); return JS_FALSE; } member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval)); /* * A little LC3 feature magic: * + Instances of java.lang.String "inherit" the standard ECMA string methods * of String.prototype. All of the ECMA string methods convert the Java * string to a JS string before performing the string operation. For example, * s = new java.lang.String("foobar"); * return s.slice(2); * + Similarly, instances of Java arrays "inherit" the standard ECMA array * methods of Array.prototype. (Not all of these methods work properly * on JavaArray objects, however, since the 'length' property is read-only.) */ if (vp) { if ((class_descriptor->type == JAVA_SIGNATURE_JAVA_LANG_STRING) && inherit_props_from_JS_natives(cx, "String", member_name, vp)) goto done; if ((class_descriptor->type == JAVA_SIGNATURE_ARRAY) && inherit_props_from_JS_natives(cx, "Array", member_name, vp)) goto done; } /* Check for access to magic prototype chain property */ if (!strcmp(member_name, "__proto__")) { proto_chain = JS_GetPrototype(cx, obj); if (vp) *vp = OBJECT_TO_JSVAL(proto_chain); goto done; } /* * See if the property looks like the explicit resolution of an * overloaded method, e.g. "max(double,double)", first as an instance method, * then as a static method. If we find such a method, it will be cached * so future accesses won't run this code. */ member_descriptor = jsj_ResolveExplicitMethod(cx, jEnv, class_descriptor, id, JS_FALSE); if (member_descriptor) goto done; member_descriptor = jsj_ResolveExplicitMethod(cx, jEnv, class_descriptor, id, JS_TRUE); if (member_descriptor) goto done; /* Is the property defined in the prototype chain? */ if (proto_chainp && prop_infop) { /* If so, follow __proto__ link to search prototype chain */ proto_chain = JS_GetPrototype(cx, obj); /* Use OBJ_LOOKUP_PROPERTY to determine if and where the property actually exists in the prototype chain. */ if (proto_chain) { if (!OBJ_LOOKUP_PROPERTY(cx, proto_chain, id, proto_chainp, &prop_infop->prop)) { return JS_FALSE; } if (prop_infop->prop) { if (!OBJ_GET_ATTRIBUTES(cx, *proto_chainp, id, prop_infop->prop, &prop_infop->attributes)) { OBJ_DROP_PROPERTY(cx, *proto_chainp, prop_infop->prop); return JS_FALSE; } if (!prop_infop->wantProp) { OBJ_DROP_PROPERTY(cx, *proto_chainp, prop_infop->prop); prop_infop->prop = NULL; } prop_infop->name = member_name; found_in_proto = JS_TRUE; goto done; } } } /* Report lack of Java member with the given property name */ JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_NO_INSTANCE_NAME, class_descriptor->name, member_name); return JS_FALSE;done: /* Success. Handle the multiple return values */ if (java_wrapperp) *java_wrapperp = java_wrapper; if (member_descriptorp) *member_descriptorp = member_descriptor; if (proto_chainp && !found_in_proto) *proto_chainp = NULL; return JS_TRUE;}JS_EXPORT_API(JSBool)JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp){ jobject java_obj; JavaMemberDescriptor *member_descriptor; JavaObjectWrapper *java_wrapper; JNIEnv *jEnv; JSObject *funobj; jsval field_val, method_val; JSBool success; JSJavaThreadState *jsj_env; JSObject *proto_chain; JSJPropertyInfo prop_info; /* printf("In JavaObject_getProperty\n"); */ /* Get the Java per-thread environment pointer for this JSContext */ jsj_env = jsj_EnterJava(cx, &jEnv); if (!jEnv) return JS_FALSE; if (vp) *vp = JSVAL_VOID; prop_info.wantProp = JS_FALSE; if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, vp, &proto_chain, &prop_info)) { jsj_ExitJava(jsj_env); return JS_FALSE; } /* Handle access to special, non-Java properties of JavaObjects, e.g. the "constructor" property of the prototype object */ if (!member_descriptor) { jsj_ExitJava(jsj_env); if (proto_chain) return JS_GetProperty(cx, proto_chain, prop_info.name, vp); return JS_TRUE; } java_obj = java_wrapper->java_obj; field_val = method_val = JSVAL_VOID; if (jaApplet && (*jEnv)->IsInstanceOf(jEnv, java_obj, jaApplet)) { jsj_JSIsCallingApplet = JS_TRUE; } /* If a field member, get the value of the field */ if (member_descriptor->field) { success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val); if (!success) { jsj_ExitJava(jsj_env); return JS_FALSE; } } /* If a method member, build a wrapper around the Java method */ if (member_descriptor->methods) { /* Create a function object with this JavaObject as its parent, so that JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */ funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj); if (!funobj) { jsj_ExitJava(jsj_env); return JS_FALSE; } method_val = OBJECT_TO_JSVAL(funobj); }#if TEST_JAVAMEMBER /* Always create a JavaMember object, even though it's inefficient */ obj = jsj_CreateJavaMember(cx, method_val, field_val); if (!obj) { jsj_ExitJava(jsj_env); return JS_FALSE; } *vp = OBJECT_TO_JSVAL(obj);#else /* !TEST_JAVAMEMBER */ if (member_descriptor->field) { if (!member_descriptor->methods) { /* Return value of Java field */ *vp = field_val; } else { /* Handle special case of access to a property that could refer to either a Java field or a method that share the same name. In Java, such ambiguity is not possible because the compiler can statically determine which is being accessed. */ obj = jsj_CreateJavaMember(cx, method_val, field_val); if (!obj) { jsj_ExitJava(jsj_env); return JS_FALSE; } *vp = OBJECT_TO_JSVAL(obj); } } else { /* Return wrapper around Java method */ *vp = method_val; }#endif /* !TEST_JAVAMEMBER */ jsj_ExitJava(jsj_env); return JS_TRUE;}JS_STATIC_DLL_CALLBACK(JSBool)JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp){ jobject java_obj; const char *member_name; JavaObjectWrapper *java_wrapper; JavaClassDescriptor *class_descriptor; JavaMemberDescriptor *member_descriptor; jsval idval; JNIEnv *jEnv; JSJavaThreadState *jsj_env; JSObject *proto_chain;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -