gpt4 book ai didi

java - 当我从 native Java 方法抛出 C++ 异常时会发生什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:46:09 25 4
gpt4 key购买 nike

假设我将 Sun 的 JVM 嵌入到 C++ 应用程序中。通过 JNI,我调用了一个 Java 方法(我自己的),该方法又调用了我在共享库中实现的 native 方法。

如果 native 方法抛出 C++ 异常会怎样?

编辑:编译器是gcc 3.4.x,jvm是sun的1.6.20。

最佳答案

Java 编译器不理解 C++ 异常,因此您必须同时处理 Java 和 C++ 异常。幸运的是,这并不太复杂。首先,我们有一个 C++ 异常,它告诉我们是否发生了 Java 异常。

#include <stdexcept>
//This is how we represent a Java exception already in progress
struct ThrownJavaException : std::runtime_error {
ThrownJavaException() :std::runtime_error("") {}
ThrownJavaException(const std::string& msg ) :std::runtime_error(msg) {}
};

以及一个在 Java 异常已经存在时抛出 C++ 异常的函数:

inline void assert_no_exception(JNIEnv * env) {
if (env->ExceptionCheck()==JNI_TRUE)
throw ThrownJavaException("assert_no_exception");
}

我们还有一个用于抛出新 Java 异常的 C++ 异常:

//used to throw a new Java exception. use full paths like:
//"java/lang/NoSuchFieldException"
//"java/lang/NullPointerException"
//"java/security/InvalidParameterException"
struct NewJavaException : public ThrownJavaException{
NewJavaException(JNIEnv * env, const char* type="", const char* message="")
:ThrownJavaException(type+std::string(" ")+message)
{
jclass newExcCls = env->FindClass(type);
if (newExcCls != NULL)
env->ThrowNew(newExcCls, message);
//if it is null, a NoClassDefFoundError was already thrown
}
};

我们还需要一个函数来吞下 C++ 异常并用 Java 异常替换它们

void swallow_cpp_exception_and_throw_java(JNIEnv * env) {
try {
throw;
} catch(const ThrownJavaException&) {
//already reported to Java, ignore
} catch(const std::bad_alloc& rhs) {
//translate OOM C++ exception to a Java exception
NewJavaException(env, "java/lang/OutOfMemoryError", rhs.what());
} catch(const std::ios_base::failure& rhs) { //sample translation
//translate IO C++ exception to a Java exception
NewJavaException(env, "java/io/IOException", rhs.what());

//TRANSLATE ANY OTHER C++ EXCEPTIONS TO JAVA EXCEPTIONS HERE

} catch(const std::exception& e) {
//translate unknown C++ exception to a Java exception
NewJavaException(env, "java/lang/Error", e.what());
} catch(...) {
//translate unknown C++ exception to a Java exception
NewJavaException(env, "java/lang/Error", "Unknown exception type");
}
}

有了上面的函数,就可以很容易的在你的C++代码中使用Java/C++混合异常了,如下所示。

extern "C" JNIEXPORT 
void JNICALL Java_MyClass_MyFunc(JNIEnv * env, jclass jc_, jstring param)
{
try { //do not let C++ exceptions outside of this function

//YOUR CODE BELOW THIS LINE. HERES SOME RANDOM CODE
if (param == NULL) //if something is wrong, throw a java exception
throw NewJavaException(env, "java/lang/NullPointerException", "param");
do_stuff(param); //might throw java or C++ exceptions
assert_no_exception(env); //throw a C++ exception if theres a java exception
do_more_stuff(param); //might throw C++ exceptions
//prefer Java exceptions where possible:
if (condition1) throw NewJavaException(env, "java/lang/NullPointerException", "condition1");
//but C++ exceptions should be fine too
if (condition0) throw std::bad_alloc("BAD_ALLOC");
//YOUR CODE ABOVE THIS LINE. HERES SOME RANDOM CODE

} catch(...) { //do not let C++ exceptions outside of this function
swallow_cpp_exception_and_throw_java(env);
}

}

如果您真的雄心勃勃,则可以跟踪更大函数的 StackTraceElement[],并获得部分堆栈跟踪。基本方法是给每个函数一个 StackTraceElement,当它们被调用时,将指向它们的指针推送到线程本地“调用堆栈”上,当它们返回时,将指针弹出。然后,更改 NewJavaException 的构造函数以复制该堆栈,并将其传递给 setStackTrace

关于java - 当我从 native Java 方法抛出 C++ 异常时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38034907/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com