This is a complement of the Elliott Hughes' answer. My answer provides a step-by-step example explaining how to catch exceptions and how to translate them between C++ and Java words using the JNI layer.
Short answer
See the correct Elliott Hughes' answer.
Reusable example
This answer and snippets are in public domain or in CC0 in order to ease reuse. All the source code here is C++03 backward compatible.
To reuse the above snippet do the following:
- Replace
mypackage::Exception
by your own C++ Exception.
- If the corresponding Java exception
my.group.mypackage.Exception
is not defined, then replace "my/group/mypackage/Exception"
by "java/lang/RuntimeException"
.
Catch exceptions from Java
See also the snippet on coliru.
void rethrow_cpp_exception_as_java_exception()
{
try
{
throw; // This allows to determine the type of the exception
}
catch (const mypackage::Exception& e) {
jclass jc = env->FindClass("my/group/mypackage/Exception");
if(jc) env->ThrowNew (jc, e.what());
/* if null => NoClassDefFoundError already thrown */
}
catch (const std::bad_alloc& e) {
jclass jc = env->FindClass("java/lang/OutOfMemoryError");
if(jc) env->ThrowNew (jc, e.what());
}
catch (const std::ios_base::failure& e) {
jclass jc = env->FindClass("java/io/IOException");
if(jc) env->ThrowNew (jc, e.what());
}
catch (const std::exception& e) {
/* unknown exception (may derive from std::exception) */
jclass jc = env->FindClass("java/lang/Error");
if(jc) env->ThrowNew (jc, e.what());
}
catch (...) {
/* Oops I missed identifying this exception! */
jclass jc = env->FindClass("java/lang/Error");
if(jc) env->ThrowNew (jc, "Unidentified exception => "
"Improve rethrow_cpp_exception_as_java_exception()" );
}
}
I thanks Mooing Duck for contribution on the above C++ code.
Adapt the JNI generated source code
The following file Java_my_group_mypackage_example.cpp
use the above rethrow_cpp_exception_as_java_exception()
function:
JNIEXPORT jlong JNICALL Java_my_group_mypackage_example_function1
(JNIEnv *env, jobject object, jlong value)
{
try {
/* ... my processing ... */
return jlong(result);
} catch(...) {
rethrow_cpp_exception_as_java_exception();
return 0;
}
}
JNIEXPORT jstring JNICALL Java_my_group_mypackage_example_function2
(JNIEnv *env, jobject object, jlong value)
{
jstring jstr = 0
try {
/* ... my processing ... */
jstr = env->NewStringUTF("my result");
} catch(...) {
rethrow_cpp_exception_as_java_exception();
}
return jstr;
}
JNIEXPORT void JNICALL Java_my_group_mypackage_example_function3
(JNIEnv *env, jobject object, jlong value)
{
try {
/* ... my processing ... */
} catch(...) {
rethrow_cpp_exception_as_java_exception();
}
}
Corresponding Java code
File example.java
package my.group.mypackage;
public class Example {
static {
System.loadLibrary("my-DLL-name");
}
public Example() {
/* ... */
}
private native int function1(int); //declare DLL functions
private native String function2(int); //using the keyword
private native void function3(int); //'native'
public void dosomething(int value) {
int result = function1(value);
String str = function2(value); //call your DLL functions
function3(value); //as any other java function
}
}
Note: "my-DLL-name
" refers to the dynamic library produced from the above C/C++ code compiled. It can be my-DLL-name.dll
on Windows or my-DLL-name.so
on GNU/Linux/Unix.
Steps
Generate example.class
from example.java
(using javac
or maven or your favorite IDE Eclipse/Netbeans/IntelliJ IDEA/...)
Generate C/C++ header file Java_my_group_mypackage_example.h
from example.class
using javah