Reputation: 23276
The following is a java code and next to it is the c code :
package Package;
public class CatchThrow {
private native void doit() throws IllegalArgumentException;
private void callBack() throws NullPointerException {
System.out.println("In call-back !");
throw new NullPointerException("CatchThrow.callBack");
}
public static void main(String args[]) {
CatchThrow c = new CatchThrow();
try {
c.doit();
} catch(Exception exc) {
System.out.println("\nIn Java : \n\t" + exc);
}
}
static {
System.loadLibrary("CatchThrow");
}
}
C code :
#include "stdio.h"
#include "Package_CatchThrow.h"
void Java_Package_CatchThrow_doit
(JNIEnv *env, jobject obj) {
jthrowable exc;
jclass cls = (*env)->GetObjectClass(env,obj);
jmethodID mid = (*env)->GetMethodID(env,cls,"callBack","()V");
if(mid == NULL) {
return;
}
(*env)->CallVoidMethod(env,obj,mid); // call the java method that throws NullPointerException
printf("After the call to Call-Back !");
exc = (*env)->ExceptionOccurred(env);
if(exc) {
jclass newExcCls;
printf("\n");
//(*env)->ExceptionDescribe(env); ----> NOTE THE COMMENTED STATEMENT
//(*env)->ExceptionClear(env); -----> NOTE THE COMMENTED STATEMENT
newExcCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");
if(newExcCls == NULL) {
return;
}
(*env)->ThrowNew(env,newExcCls,"thrown from c code");
}
}
When i build and run the above program I get the following output :
In call-back !
After the call to Call-Back !
In Java :
java.lang.IllegalArgumentException: thrown from c code
From the output : C code calls the java function callBack. There the first statement gets printed. After the call returns the statement next to the call i.e After the call to Call-Back !
gets printed. But what happened to the statement throw new NullPointerException("CatchThrow.callBack");
in the java function callBack ? Why doesn't it print the exception ?
But if i remove the comments from the statements
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
commented, I get the desired output :
In call-back !
After the call to Call-Back !
Exception in thread "main" java.lang.NullPointerException: CatchThrow.callBack
at Package.CatchThrow.callBack(CatchThrow.java:14)
at Package.CatchThrow.doit(Native Method)
at Package.CatchThrow.main(CatchThrow.java:20)
In Java :
java.lang.IllegalArgumentException: thrown from c code
Why is that ?
What is the role of those two statements ? And why doesn't the exception get printed in the absence of those 2 statements ?
Upvotes: 2
Views: 3412
Reputation: 3363
Your new NullPointerException("CatchThrow.callBack");
never touches the Java runtime and is handled completely in JNI space.
As such, no exception details will be printed unless you call the JNI ExceptionDescribe function:
(*env)->ExceptionDescribe(env);
You can't return multiple exceptions from the JNI so the only exception information that comes back to your try/catch block in the Java runtime is the one you create later on with:
(*env)->ThrowNew(env,newExcCls,"thrown from c code");
A pending exception raised through the JNI (by calling ThrowNew, for example) does not immediately disrupt the native method execution. This is different from how exceptions behave in the Java programming language. When an exception is thrown in the Java programming language, the virtual machine automatically transfers the control flow to the nearest enclosing try/catch statement that matches the exception type. The virtual machine then clears the pending exception and executes the exception handler. In contrast, JNI programmers must explicitly implement the control flow after an exception has occurred.
From the JNI documentation on exceptions
Upvotes: 2
Reputation: 328800
According to the documentation, ExceptionDescribe
Prints an exception and a backtrace of the stack to a system error-reporting channel, such as
stderr
. This is a convenience routine provided for debugging.
ExceptionClear
:
Clears any exception that is currently being thrown. If no exception is currently being thrown, this routine has no effect.
This is usually not what you want. I suggest to create IllegalArgumentException
with the NPE as cause. In Java, you'd write this like so:
throw new IllegalArgumentException( "thrown from c code", exc );
That way, the inner and outer exceptions (incl. stack traces) are available at the Java level where you can examine them.
Upvotes: 0