jobject EnumMapper::mapEnum(const char *clazzName, int index) { // The fact that we can even do this depends upon a couple of assumptions, // mainly some knowledge about the orderin of the various constants in // both the C and Java enums. Should those values ever change, // the World Will End. std::string methodSig("()[L"); methodSig.append(clazzName); methodSig.append(";"); JNIEnv *env = JNIUtil::getEnv(); // Create a local frame for our references env->PushLocalFrame(LOCAL_FRAME_SIZE); if (JNIUtil::isJavaExceptionThrown()) return NULL; jclass clazz = env->FindClass(clazzName); if (JNIUtil::isJavaExceptionThrown()) POP_AND_RETURN_NULL; jmethodID mid = env->GetStaticMethodID(clazz, "values", methodSig.c_str()); if (JNIUtil::isJavaExceptionThrown()) POP_AND_RETURN_NULL; jobjectArray jvalues = (jobjectArray) env->CallStaticObjectMethod(clazz, mid); if (JNIUtil::isJavaExceptionThrown()) POP_AND_RETURN_NULL; jobject jthing = env->GetObjectArrayElement(jvalues, index); if (JNIUtil::isJavaExceptionThrown()) POP_AND_RETURN_NULL; return env->PopLocalFrame(jthing); }
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; }
void ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage) { // Only throw this exception if one hasn't already been thrown, so we don't // mask a previous exception/error. if (env->ExceptionCheck()) return; // If the error code we get is for an Out Of Memory error, try to throw an // OutOfMemoryError. The JVM may have enough memory to create this error. if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) { jclass clazz = env->FindClass("java/lang/OutOfMemoryError"); if (clazz) { env->ThrowNew(clazz, aMessage); } env->DeleteLocalRef(clazz); return; } // If the error was not handled above, then create an XPCOMException with the // given error code and message. // Create parameters and method signature. Max of 2 params. The error code // comes before the message string. PRInt64 errorCode = aErrorCode ? aErrorCode : NS_ERROR_FAILURE; nsCAutoString methodSig("(J"); jstring message = nsnull; if (aMessage) { message = env->NewStringUTF(aMessage); if (!message) { return; } methodSig.AppendLiteral("Ljava/lang/String;"); } methodSig.AppendLiteral(")V"); // In some instances (such as in shutdownXPCOM() and termEmbedding()), we // will need to throw an exception when JavaXPCOM has already been // terminated. In such a case, 'xpcomExceptionClass' will be null. So we // reset it temporarily in order to throw the appropriate exception. if (xpcomExceptionClass == nsnull) { xpcomExceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException"); if (!xpcomExceptionClass) { return; } } // create exception object jthrowable throwObj = nsnull; jmethodID mid = env->GetMethodID(xpcomExceptionClass, "<init>", methodSig.get()); if (mid) { throwObj = (jthrowable) env->NewObject(xpcomExceptionClass, mid, errorCode, message); } NS_ASSERTION(throwObj, "Failed to create XPCOMException object"); // throw exception if (throwObj) { env->Throw(throwObj); } }