value CallMember(jobject inObject, value inArgs) { JNIEnv *env = GetEnv(); jvalue jargs[MAX]; if (!HaxeToJNIArgs(env,inArgs,jargs)) { CleanStringArgs(); ELOG("CallMember - bad argument list"); return alloc_null(); } value result = 0; switch(mReturn) { case jniVoid: result = alloc_null(); env->CallVoidMethodA(inObject, mMethod, jargs); break; case jniObject: result = JObjectToHaxe(env->CallObjectMethodA(inObject,mMethod, jargs)); break; case jniObjectString: result = JStringToHaxe(env,env->CallObjectMethodA(inObject, mMethod, jargs)); break; case jniObjectArray: result = JArrayToHaxe(env->CallObjectMethodA(inObject, mMethod, jargs)); break; case jniBoolean: result = alloc_bool(env->CallBooleanMethodA(inObject, mMethod, jargs)); break; case jniByte: result = alloc_int(env->CallByteMethodA(inObject, mMethod, jargs)); break; case jniChar: result = alloc_int(env->CallCharMethodA(inObject, mMethod, jargs)); break; case jniShort: result = alloc_int(env->CallShortMethodA(inObject, mMethod, jargs)); break; case jniInt: result = alloc_int(env->CallIntMethodA(mClass, mMethod, jargs)); break; case jniLong: result = alloc_int(env->CallLongMethodA(inObject, mMethod, jargs)); break; case jniFloat: result = alloc_float(env->CallFloatMethodA(inObject, mMethod, jargs)); break; case jniDouble: result = alloc_float(env->CallDoubleMethodA(inObject, mMethod, jargs)); break; } CleanStringArgs(); return result; }
Handle<Value> TiAndroidRequeststoragepermissionModule::hasStoragePermission(const Arguments& args) { LOGD(TAG, "hasStoragePermission()"); HandleScope scope; JNIEnv *env = titanium::JNIScope::getEnv(); if (!env) { return titanium::JSException::GetJNIEnvironmentError(); } static jmethodID methodID = NULL; if (!methodID) { methodID = env->GetMethodID(TiAndroidRequeststoragepermissionModule::javaClass, "hasStoragePermission", "()Z"); if (!methodID) { const char *error = "Couldn't find proxy method 'hasStoragePermission' with signature '()Z'"; LOGE(TAG, error); return titanium::JSException::Error(error); } } titanium::Proxy* proxy = titanium::Proxy::unwrap(args.Holder()); jvalue* jArguments = 0; jobject javaProxy = proxy->getJavaObject(); jboolean jResult = (jboolean)env->CallBooleanMethodA(javaProxy, methodID, jArguments); if (!JavaObject::useGlobalRefs) { env->DeleteLocalRef(javaProxy); } if (env->ExceptionCheck()) { Handle<Value> jsException = titanium::JSException::fromJavaException(); env->ExceptionClear(); return jsException; } Handle<Boolean> v8Result = titanium::TypeConverter::javaBooleanToJsBoolean(env, jResult); return v8Result; }
virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { print_line("attempt to call "+String(p_method)); r_error.error=Variant::CallError::CALL_OK; Map<StringName,MethodData >::Element *E=method_map.find(p_method); if (!E) { print_line("no exists"); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } int ac = E->get().argtypes.size(); if (ac<p_argcount) { print_line("fewargs"); r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=ac; return Variant(); } if (ac>p_argcount) { print_line("manyargs"); r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=ac; return Variant(); } for(int i=0;i<p_argcount;i++) { if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=i; r_error.expected=E->get().argtypes[i]; } } jvalue *v=NULL; if (p_argcount) { v=(jvalue*)alloca( sizeof(jvalue)*p_argcount ); } for(int i=0;i<p_argcount;i++) { switch(E->get().argtypes[i]) { case Variant::BOOL: { v[i].z=*p_args[i]; } break; case Variant::INT: { v[i].i=*p_args[i]; } break; case Variant::REAL: { v[i].f=*p_args[i]; } break; case Variant::STRING: { String s = *p_args[i]; jstring jStr = env->NewStringUTF(s.utf8().get_data()); v[i].l=jStr; } break; case Variant::STRING_ARRAY: { DVector<String> sarray = *p_args[i]; jobjectArray arr = env->NewObjectArray(sarray.size(),env->FindClass("java/lang/String"),env->NewStringUTF("")); for(int j=0;j<sarray.size();j++) { env->SetObjectArrayElement(arr,j,env->NewStringUTF( sarray[i].utf8().get_data() )); } v[i].l=arr; } break; case Variant::INT_ARRAY: { DVector<int> array = *p_args[i]; jintArray arr = env->NewIntArray(array.size()); DVector<int>::Read r = array.read(); env->SetIntArrayRegion(arr,0,array.size(),r.ptr()); v[i].l=arr; } break; case Variant::REAL_ARRAY: { DVector<float> array = *p_args[i]; jfloatArray arr = env->NewFloatArray(array.size()); DVector<float>::Read r = array.read(); env->SetFloatArrayRegion(arr,0,array.size(),r.ptr()); v[i].l=arr; } break; default: { ERR_FAIL_V(Variant()); } break; } } print_line("calling method!!"); Variant ret; switch(E->get().ret_type) { case Variant::NIL: { print_line("call void"); env->CallVoidMethodA(instance,E->get().method,v); } break; case Variant::BOOL: { ret = env->CallBooleanMethodA(instance,E->get().method,v); print_line("call bool"); } break; case Variant::INT: { ret = env->CallIntMethodA(instance,E->get().method,v); print_line("call int"); } break; case Variant::REAL: { ret = env->CallFloatMethodA(instance,E->get().method,v); } break; case Variant::STRING: { jobject o = env->CallObjectMethodA(instance,E->get().method,v); String singname = env->GetStringUTFChars((jstring)o, NULL ); } break; case Variant::STRING_ARRAY: { jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v); int stringCount = env->GetArrayLength(arr); DVector<String> sarr; for (int i=0; i<stringCount; i++) { jstring string = (jstring) env->GetObjectArrayElement(arr, i); const char *rawString = env->GetStringUTFChars(string, 0); sarr.push_back(String(rawString)); } ret=sarr; } break; case Variant::INT_ARRAY: { jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); DVector<int> sarr; sarr.resize(fCount); DVector<int>::Write w = sarr.write(); env->GetIntArrayRegion(arr,0,fCount,w.ptr()); w = DVector<int>::Write(); ret=sarr; } break; case Variant::REAL_ARRAY: { jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); DVector<float> sarr; sarr.resize(fCount); DVector<float>::Write w = sarr.write(); env->GetFloatArrayRegion(arr,0,fCount,w.ptr()); w = DVector<float>::Write(); ret=sarr; } break; default: { print_line("failure.."); ERR_FAIL_V(Variant()); } break; } print_line("success"); return ret; }
virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { //print_line("attempt to call "+String(p_method)); ERR_FAIL_COND_V(!instance,Variant()); r_error.error=Variant::CallError::CALL_OK; Map<StringName,MethodData >::Element *E=method_map.find(p_method); if (!E) { print_line("no exists"); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } int ac = E->get().argtypes.size(); if (ac<p_argcount) { print_line("fewargs"); r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=ac; return Variant(); } if (ac>p_argcount) { print_line("manyargs"); r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=ac; return Variant(); } for(int i=0;i<p_argcount;i++) { if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=i; r_error.expected=E->get().argtypes[i]; } } jvalue *v=NULL; if (p_argcount) { v=(jvalue*)alloca( sizeof(jvalue)*p_argcount ); } JNIEnv *env = ThreadAndroid::get_env(); int res = env->PushLocalFrame(16); ERR_FAIL_COND_V(res!=0,Variant()); //print_line("argcount "+String::num(p_argcount)); List<jobject> to_erase; for(int i=0;i<p_argcount;i++) { jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]); v[i] = vr.val; if (vr.obj) to_erase.push_back(vr.obj); } //print_line("calling method!!"); Variant ret; switch(E->get().ret_type) { case Variant::NIL: { //print_line("call void"); env->CallVoidMethodA(instance,E->get().method,v); } break; case Variant::BOOL: { ret = env->CallBooleanMethodA(instance,E->get().method,v); //print_line("call bool"); } break; case Variant::INT: { ret = env->CallIntMethodA(instance,E->get().method,v); //print_line("call int"); } break; case Variant::REAL: { ret = env->CallFloatMethodA(instance,E->get().method,v); } break; case Variant::STRING: { jobject o = env->CallObjectMethodA(instance,E->get().method,v); String str = env->GetStringUTFChars((jstring)o, NULL ); ret=str; env->DeleteLocalRef(o); } break; case Variant::STRING_ARRAY: { jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance,E->get().method,v); ret = _jobject_to_variant(env, arr); env->DeleteLocalRef(arr); } break; case Variant::INT_ARRAY: { jintArray arr = (jintArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); DVector<int> sarr; sarr.resize(fCount); DVector<int>::Write w = sarr.write(); env->GetIntArrayRegion(arr,0,fCount,w.ptr()); w = DVector<int>::Write(); ret=sarr; env->DeleteLocalRef(arr); } break; case Variant::REAL_ARRAY: { jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance,E->get().method,v); int fCount = env->GetArrayLength(arr); DVector<float> sarr; sarr.resize(fCount); DVector<float>::Write w = sarr.write(); env->GetFloatArrayRegion(arr,0,fCount,w.ptr()); w = DVector<float>::Write(); ret=sarr; env->DeleteLocalRef(arr); } break; case Variant::DICTIONARY: { //print_line("call dictionary"); jobject obj = env->CallObjectMethodA(instance, E->get().method, v); ret = _jobject_to_variant(env, obj); env->DeleteLocalRef(obj); } break; default: { print_line("failure.."); env->PopLocalFrame(NULL); ERR_FAIL_V(Variant()); } break; } while (to_erase.size()) { env->DeleteLocalRef(to_erase.front()->get()); to_erase.pop_front(); } env->PopLocalFrame(NULL); //print_line("success"); return ret; }
bool JavaClass::_call_method(JavaObject* p_instance,const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error,Variant& ret) { Map<StringName,List<MethodInfo> >::Element *M=methods.find(p_method); if (!M) return false; JNIEnv *env = ThreadAndroid::get_env(); MethodInfo *method=NULL; for (List<MethodInfo>::Element *E=M->get().front(); E; E=E->next()) { if (!p_instance && !E->get()._static) { r_error.error=Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL; continue; } int pc = E->get().param_types.size(); if (pc>p_argcount) { r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument=pc; continue; } if (pc<p_argcount) { r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument=pc; continue; } uint32_t *ptypes=E->get().param_types.ptr(); bool valid=true; for(int i=0; i<pc; i++) { Variant::Type arg_expected=Variant::NIL; switch(ptypes[i]) { case ARG_TYPE_VOID: { //bug? } break; case ARG_TYPE_BOOLEAN: { if (p_args[i]->get_type()!=Variant::BOOL) arg_expected=Variant::BOOL; } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE: case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR: case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT: case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT: case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG: case ARG_TYPE_BYTE: case ARG_TYPE_CHAR: case ARG_TYPE_SHORT: case ARG_TYPE_INT: case ARG_TYPE_LONG: { if (!p_args[i]->is_num()) arg_expected=Variant::INT; } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT: case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE: case ARG_TYPE_FLOAT: case ARG_TYPE_DOUBLE: { if (!p_args[i]->is_num()) arg_expected=Variant::REAL; } break; case ARG_TYPE_STRING: { if (p_args[i]->get_type()!=Variant::STRING) arg_expected=Variant::STRING; } break; case ARG_TYPE_CLASS: { if (p_args[i]->get_type()!=Variant::OBJECT) arg_expected=Variant::OBJECT; else { Ref<Reference> ref = *p_args[i]; if (!ref.is_null()) { if (ref->cast_to<JavaObject>() ) { Ref<JavaObject> jo=ref; //could be faster jclass c = env->FindClass(E->get().param_sigs[i].operator String().utf8().get_data()); if (!c || !env->IsInstanceOf(jo->instance,c)) { arg_expected=Variant::OBJECT; } else { //ok } } else { arg_expected=Variant::OBJECT; } } } } break; default: { if (p_args[i]->get_type()!=Variant::ARRAY) arg_expected=Variant::ARRAY; } break; } if (arg_expected!=Variant::NIL) { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument=i; r_error.expected=arg_expected; valid=false; break; } } if (!valid) continue; method=&E->get(); break; } if (!method) return true; //no version convinces r_error.error=Variant::CallError::CALL_OK; jvalue *argv=NULL; if (method->param_types.size()) { argv=(jvalue*)alloca( sizeof(jvalue)*method->param_types.size() ); } List<jobject> to_free; for(int i=0; i<method->param_types.size(); i++) { switch(method->param_types[i]) { case ARG_TYPE_VOID: { //can't happen argv[i].l=NULL; //I hope this works } break; case ARG_TYPE_BOOLEAN: { argv[i].z=*p_args[i]; } break; case ARG_TYPE_BYTE: { argv[i].b=*p_args[i]; } break; case ARG_TYPE_CHAR: { argv[i].c=*p_args[i]; } break; case ARG_TYPE_SHORT: { argv[i].s=*p_args[i]; } break; case ARG_TYPE_INT: { argv[i].i=*p_args[i]; } break; case ARG_TYPE_LONG: { argv[i].j=*p_args[i]; } break; case ARG_TYPE_FLOAT: { argv[i].f=*p_args[i]; } break; case ARG_TYPE_DOUBLE: { argv[i].d=*p_args[i]; } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BOOLEAN: { jclass bclass = env->FindClass("java/lang/Boolean"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V"); jvalue val; val.z = (bool)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE: { jclass bclass = env->FindClass("java/lang/Byte"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V"); jvalue val; val.b = (int)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR: { jclass bclass = env->FindClass("java/lang/Character"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V"); jvalue val; val.c = (int)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT: { jclass bclass = env->FindClass("java/lang/Short"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V"); jvalue val; val.s = (int)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT: { jclass bclass = env->FindClass("java/lang/Integer"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V"); jvalue val; val.i = (int)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG: { jclass bclass = env->FindClass("java/lang/Long"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V"); jvalue val; val.j = (int64_t)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT: { jclass bclass = env->FindClass("java/lang/Float"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V"); jvalue val; val.f = (float)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE: { jclass bclass = env->FindClass("java/lang/Double"); jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V"); jvalue val; val.d = (double)(*p_args[i]); jobject obj = env->NewObjectA(bclass, ctor, &val); argv[i].l = obj; to_free.push_back(obj); } break; case ARG_TYPE_STRING: { String s = *p_args[i]; jstring jStr = env->NewStringUTF(s.utf8().get_data()); argv[i].l=jStr; to_free.push_back(jStr); } break; case ARG_TYPE_CLASS: { Ref<JavaObject> jo=*p_args[i]; if (jo.is_valid()) { argv[i].l=jo->instance; } else { argv[i].l=NULL; //I hope this works } } break; case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: { Array arr = *p_args[i]; jbooleanArray a = env->NewBooleanArray(arr.size()); for(int j=0; j<arr.size(); j++) { jboolean val = arr[j]; env->SetBooleanArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_BYTE: { Array arr = *p_args[i]; jbyteArray a = env->NewByteArray(arr.size()); for(int j=0; j<arr.size(); j++) { jbyte val = arr[j]; env->SetByteArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_CHAR: { Array arr = *p_args[i]; jcharArray a = env->NewCharArray(arr.size()); for(int j=0; j<arr.size(); j++) { jchar val = arr[j]; env->SetCharArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_SHORT: { Array arr = *p_args[i]; jshortArray a = env->NewShortArray(arr.size()); for(int j=0; j<arr.size(); j++) { jshort val = arr[j]; env->SetShortArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_INT: { Array arr = *p_args[i]; jintArray a = env->NewIntArray(arr.size()); for(int j=0; j<arr.size(); j++) { jint val = arr[j]; env->SetIntArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_LONG: { Array arr = *p_args[i]; jlongArray a = env->NewLongArray(arr.size()); for(int j=0; j<arr.size(); j++) { jlong val = arr[j]; env->SetLongArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: { Array arr = *p_args[i]; jfloatArray a = env->NewFloatArray(arr.size()); for(int j=0; j<arr.size(); j++) { jfloat val = arr[j]; env->SetFloatArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: { Array arr = *p_args[i]; jdoubleArray a = env->NewDoubleArray(arr.size()); for(int j=0; j<arr.size(); j++) { jdouble val = arr[j]; env->SetDoubleArrayRegion(a,j,1,&val); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_STRING: { Array arr = *p_args[i]; jobjectArray a = env->NewObjectArray(arr.size(),env->FindClass("java/lang/String"),NULL); for(int j=0; j<arr.size(); j++) { String s = arr[j]; jstring jStr = env->NewStringUTF(s.utf8().get_data()); env->SetObjectArrayElement(a,j,jStr); to_free.push_back(jStr); } argv[i].l=a; to_free.push_back(a); } break; case ARG_ARRAY_BIT|ARG_TYPE_CLASS: { argv[i].l=NULL; } break; } } r_error.error=Variant::CallError::CALL_OK; bool success=true; switch(method->return_type) { case ARG_TYPE_VOID: { if (method->_static) { env->CallStaticVoidMethodA(_class,method->method,argv); } else { env->CallVoidMethodA(p_instance->instance,method->method,argv); } ret=Variant(); } break; case ARG_TYPE_BOOLEAN: { if (method->_static) { ret=env->CallStaticBooleanMethodA(_class,method->method,argv); } else { ret=env->CallBooleanMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_BYTE: { if (method->_static) { ret=env->CallStaticByteMethodA(_class,method->method,argv); } else { ret=env->CallByteMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_CHAR: { if (method->_static) { ret=env->CallStaticCharMethodA(_class,method->method,argv); } else { ret=env->CallCharMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_SHORT: { if (method->_static) { ret=env->CallStaticShortMethodA(_class,method->method,argv); } else { ret=env->CallShortMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_INT: { if (method->_static) { ret=env->CallStaticIntMethodA(_class,method->method,argv); } else { ret=env->CallIntMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_LONG: { if (method->_static) { ret=env->CallStaticLongMethodA(_class,method->method,argv); } else { ret=env->CallLongMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_FLOAT: { if (method->_static) { ret=env->CallStaticFloatMethodA(_class,method->method,argv); } else { ret=env->CallFloatMethodA(p_instance->instance,method->method,argv); } } break; case ARG_TYPE_DOUBLE: { if (method->_static) { ret=env->CallStaticDoubleMethodA(_class,method->method,argv); } else { ret=env->CallDoubleMethodA(p_instance->instance,method->method,argv); } } break; default: { jobject obj; if (method->_static) { obj=env->CallStaticObjectMethodA(_class,method->method,argv); } else { obj=env->CallObjectMethodA(p_instance->instance,method->method,argv); } if (!obj) { ret=Variant(); } else { if (!_convert_object_to_variant(env, obj, ret,method->return_type)) { ret=Variant(); r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; success=false; } env->DeleteLocalRef(obj); } } break; } for(List<jobject>::Element *E=to_free.front(); E; E=E->next()) { env->DeleteLocalRef(E->get()); } return success; }
NS_IMETHODIMP nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, const XPTMethodDescriptor *aMethodInfo, nsXPTCMiniVariant *aParams) { #ifdef DEBUG_JAVAXPCOM const char* ifaceName; mIInfo->GetNameShared(&ifaceName); LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); #endif nsresult rv = NS_OK; JNIEnv* env = GetJNIEnv(); jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); nsCAutoString methodSig("("); // Create jvalue array to hold Java params PRUint8 paramCount = aMethodInfo->num_args; jvalue* java_params = nsnull; const nsXPTParamInfo* retvalInfo = nsnull; if (paramCount) { java_params = new jvalue[paramCount]; if (!java_params) return NS_ERROR_OUT_OF_MEMORY; for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) { const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; if (!paramInfo.IsRetval()) { rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, aParams[i], java_params[i], methodSig); } else { retvalInfo = ¶mInfo; } } NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed"); } // Finish method signature if (NS_SUCCEEDED(rv)) { methodSig.Append(')'); if (retvalInfo) { nsCAutoString retvalSig; rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams, retvalSig); methodSig.Append(retvalSig); } else { methodSig.Append('V'); } NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed"); } // Get Java method to call jmethodID mid = nsnull; if (NS_SUCCEEDED(rv)) { nsCAutoString methodName; if (XPT_MD_IS_GETTER(aMethodInfo->flags) || XPT_MD_IS_SETTER(aMethodInfo->flags)) { if (XPT_MD_IS_GETTER(aMethodInfo->flags)) methodName.AppendLiteral("get"); else methodName.AppendLiteral("set"); methodName.AppendASCII(aMethodInfo->name); methodName.SetCharAt(toupper(methodName[3]), 3); } else { methodName.AppendASCII(aMethodInfo->name); methodName.SetCharAt(tolower(methodName[0]), 0); } // If it's a Java keyword, then prepend an underscore if (gJavaKeywords->GetEntry(methodName.get())) { methodName.Insert('_', 0); } jclass clazz = env->GetObjectClass(javaObject); if (clazz) mid = env->GetMethodID(clazz, methodName.get(), methodSig.get()); NS_ASSERTION(mid, "Failed to get requested method for Java object"); if (!mid) rv = NS_ERROR_FAILURE; } // Call method jvalue retval; if (NS_SUCCEEDED(rv)) { if (!retvalInfo) { env->CallVoidMethodA(javaObject, mid, java_params); } else { switch (retvalInfo->GetType().TagPart()) { case nsXPTType::T_I8: retval.b = env->CallByteMethodA(javaObject, mid, java_params); break; case nsXPTType::T_I16: case nsXPTType::T_U8: retval.s = env->CallShortMethodA(javaObject, mid, java_params); break; case nsXPTType::T_I32: case nsXPTType::T_U16: retval.i = env->CallIntMethodA(javaObject, mid, java_params); break; case nsXPTType::T_I64: case nsXPTType::T_U32: retval.j = env->CallLongMethodA(javaObject, mid, java_params); break; case nsXPTType::T_FLOAT: retval.f = env->CallFloatMethodA(javaObject, mid, java_params); break; case nsXPTType::T_U64: case nsXPTType::T_DOUBLE: retval.d = env->CallDoubleMethodA(javaObject, mid, java_params); break; case nsXPTType::T_BOOL: retval.z = env->CallBooleanMethodA(javaObject, mid, java_params); break; case nsXPTType::T_CHAR: case nsXPTType::T_WCHAR: retval.c = env->CallCharMethodA(javaObject, mid, java_params); break; case nsXPTType::T_CHAR_STR: case nsXPTType::T_WCHAR_STR: case nsXPTType::T_IID: case nsXPTType::T_ASTRING: case nsXPTType::T_DOMSTRING: case nsXPTType::T_UTF8STRING: case nsXPTType::T_CSTRING: case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: retval.l = env->CallObjectMethodA(javaObject, mid, java_params); break; case nsXPTType::T_VOID: retval.j = env->CallLongMethodA(javaObject, mid, java_params); break; default: NS_WARNING("Unhandled retval type"); break; } } // Check for exception from called Java function jthrowable exp = env->ExceptionOccurred(); if (exp) { // If the exception is an instance of XPCOMException, then get the // nsresult from the exception instance. Else, default to // NS_ERROR_FAILURE. if (env->IsInstanceOf(exp, xpcomExceptionClass)) { jfieldID fid; fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J"); if (fid) { rv = env->GetLongField(exp, fid); } else { rv = NS_ERROR_FAILURE; } NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException"); } else { rv = NS_ERROR_FAILURE; } } } // Handle any 'inout', 'out' and 'retval' params if (NS_SUCCEEDED(rv)) { for (PRUint8 i = 0; i < paramCount; i++) { const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in' continue; // If param is null, then caller is not expecting an output value. if (aParams[i].val.p == nsnull) continue; if (!paramInfo.IsRetval()) { rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, aParams[i], java_params[i]); } else { rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, aParams[i], retval); } } NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed"); } if (java_params) delete [] java_params; #ifdef DEBUG if (env->ExceptionCheck()) env->ExceptionDescribe(); #endif env->ExceptionClear(); LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); return rv; }