I am trying to understand the jni with some examples. I am trying to get the java stack trace using jni and so this is what I was doing
HelloJNI.java
package test.com.jni;
public class HelloJNI {
static {
System.loadLibrary("hello"); // Load native library at runtime
}
private native StackTraceElement[] getStackTraceNative(Throwable throwable);
private native void printStackTraceNative(Throwable throwable);
public static void main(String[] args) {
test();
}
public static void test() {
new HelloJNI().printStackTraceNative(new Throwable()); //Invoke native method
new HelloJNI().getStackTraceNative(new Throwable());
}
}
Native code (keeping the error handling out for simplicity)
test_com_jni_HelloJNI.c
JNIEXPORT jobjectArray JNICALL Java_test_com_jni_HelloJNI_getStackTraceNative (JNIEnv * env, jobject object, jthrowable exception) {
jclass exceptionClazz = (*env)->GetObjectClass(env, exception);
jmethodID getStackTraceMethod = (*env)->GetMethodID(env, exceptionClazz, "getStackTrace", "()[Ljava.lang.StackTraceElement");
jobjectArray stacktraces = (*env)->CallObjectMethod(env, exception, getStackTraceMethod);
return stacktraces;
}
JNIEXPORT void JNICALL Java_test_com_jni_HelloJNI_printStackTraceNative (JNIEnv * env, jobject object, jthrowable exception) {
jclass exceptionClazz = (*env)->GetObjectClass(env, exception); // can't fail
jmethodID printStackTraceMethod = (*env)->GetMethodID(env, exceptionClazz, "printStackTrace", "()V");
(*env)->CallVoidMethod(env, exception, printStackTraceMethod);
}
Now in this code native printStackTraceNative
method works and it prints the stack trace however, getStackTraceNative
doesn't. When I check the core dump file it says that java has thrown an exception java/lang/NoSuchMethodError
for getStackTrace
. I am confused because the parameter I am passing to getStackTraceNative method is of the type throwable and throwable should have the method getStackTrace
.
What concept I possibly be missing here, any help on this is appreciated. Thanks
You got the method signature wrong. In method signatures the periods in the qualified class name are replaced by forward slashes. The signature for getStackTrace
is therefore ()[Ljava/lang/StackTraceElement;
(also note the semicolon)
You can get the method signatures from class files with javap
with -s
option:
javap -classpath '/path/to/jre/lib/rt.jar' -s java.lang.Throwable