Java director exception handling improvements
When a director method throws an exception and it is caught by DirectorException and passed back to Java using DirectorException::raiseJavaException, the Java stack trace now contains the original source line that threw the exception. Director exception handling code improved slightly to add some missing ExceptionClear calls before calling JNI code.
This commit is contained in:
parent
7d6808daab
commit
7aa28e37ec
7 changed files with 74 additions and 44 deletions
|
|
@ -3843,7 +3843,6 @@ handle the mapping of Java exceptions into C++ exceptions.
|
|||
%feature("director:except") MyClass::method(int x) {
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
if (Swig::ExceptionMatches(jenv, $error, "java/lang/IndexOutOfBoundsException"))
|
||||
throw std::out_of_range(Swig::JavaExceptionMessage(jenv, $error).message());
|
||||
if (Swig::ExceptionMatches(jenv, $error, "$packagepath/MyJavaException"))
|
||||
|
|
@ -3921,7 +3920,6 @@ is used in the feature code. Consider the following, which also happens to be th
|
|||
%feature("director:except") %{
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
$directorthrowshandlers
|
||||
Swig::DirectorException::raise(jenv, $error);
|
||||
}
|
||||
|
|
@ -3970,7 +3968,6 @@ the resulting code generated in the director method after calling up to Java wil
|
|||
<pre>
|
||||
jthrowable swigerror = jenv->ExceptionOccurred();
|
||||
if (swigerror) {
|
||||
jenv->ExceptionClear();
|
||||
if (Swig::ExceptionMatches(jenv, swigerror, "java/lang/IndexOutOfBoundsException")) {
|
||||
throw std::out_of_range(Swig::JavaExceptionMessage(jenv, swigerror).message());
|
||||
}
|
||||
|
|
@ -3992,7 +3989,7 @@ this potential fate.
|
|||
<p>Because the default code generation maps any unhandled Java exceptions to
|
||||
<code>Swig::DirectorException</code>, any director methods that have exception
|
||||
specifications may cause program termination. To simply ignore
|
||||
unexpected exceptions, the default handling can be changed with:
|
||||
unexpected exceptions, the default handling can be changed by adding:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
|
|
@ -4068,14 +4065,10 @@ DEFINE_EXCEPTION(ExceptionA)
|
|||
DEFINE_EXCEPTION(ExceptionB)
|
||||
DEFINE_EXCEPTION(Unexpected)
|
||||
|
||||
// Mark three methods to map director thrown exceptions.
|
||||
%feature("director:except") MyClass::meth1(int);
|
||||
%feature("director:except") MyClass::meth2;
|
||||
%feature("director:except") meth3;
|
||||
|
||||
%typemap(directorthrows) MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected %{
|
||||
if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname"))
|
||||
if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname")) {
|
||||
throw $1_type(Swig::JavaExceptionMessage(jenv, $error).message());
|
||||
}
|
||||
%}
|
||||
|
||||
DECLARE_EXCEPTION(ExceptionA)
|
||||
|
|
@ -4084,6 +4077,8 @@ DECLARE_EXCEPTION(Unexpected)
|
|||
|
||||
%catches(MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected) MyClass::meth2();
|
||||
|
||||
%feature("director") MyClass;
|
||||
|
||||
%inline {
|
||||
class MyClass {
|
||||
public:
|
||||
|
|
@ -4100,13 +4095,13 @@ DECLARE_EXCEPTION(Unexpected)
|
|||
In this case the three different "directorthrows" typemaps will be used
|
||||
to generate the three different exception handlers for
|
||||
<code>meth1</code>, <code>meth2</code> and <code>meth3</code>. The generated
|
||||
handlers will have "if" blocks for each exception type specified, in
|
||||
handlers will have "if" blocks for each exception type, where the exception types are listed in either
|
||||
the exception specification or <code>%catches</code> feature.
|
||||
</p>
|
||||
|
||||
<p>Note that the "directorthrows" typemaps are important
|
||||
only if it is important for the exceptions passed through the C++
|
||||
layer to be mapped to distinct C++ exceptions. If director methods
|
||||
layer need to be mapped to distinct C++ exceptions. If director methods
|
||||
are being called by C++ code that is itself wrapped in a
|
||||
SWIG generated Java wrapper and access is always through this wrapper,
|
||||
the default <code>Swig::DirectorException</code> class provides enough information
|
||||
|
|
|
|||
|
|
@ -126,19 +126,28 @@ public class java_director_exception_feature_nspace_runme {
|
|||
try { b.genericpong(1); fail("No exception thrown in genericpong(1)"); }
|
||||
catch (MyJavaException1 e) {
|
||||
failif( ! java_director_exception_feature_nspace_Consts.GENERICPONGEXCP1.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_nspace_MyFooDirectorImpl.genericpong(java_director_exception_feature_nspace_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(2); fail("No exception thrown in genericpong(2)");}
|
||||
catch (java_director_exception_feature_nspace_NewCheckedException e) {
|
||||
failif( ! java_director_exception_feature_nspace_Consts.GENERICPONGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_nspace_MyFooDirectorImpl.genericpong(java_director_exception_feature_nspace_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(3); fail("No exception thrown in genericpong(3)");}
|
||||
catch (java_director_exception_feature_nspace_NewUncheckedException e) {
|
||||
failif( ! java_director_exception_feature_nspace_Consts.GENERICPONGEXCP3.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_nspace_MyFooDirectorImpl.genericpong(java_director_exception_feature_nspace_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(4); fail("No exception thrown in genericpong(4)");}
|
||||
catch (RuntimeException e) {
|
||||
failif ( e.getClass() != RuntimeException.class, "Exception " + e + " is not exactly RumtimeException");
|
||||
failif( ! java_director_exception_feature_nspace_Consts.GENERICPONGEXCP4.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
failif ( e.getClass() != RuntimeException.class, "Exception " + e + " is not exactly RuntimeException");
|
||||
failif( ! "Unspecified DirectorException message".equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -127,19 +127,28 @@ public class java_director_exception_feature_runme {
|
|||
try { b.genericpong(1); fail("No exception thrown in genericpong(1)"); }
|
||||
catch (MyJavaException1 e) {
|
||||
failif( ! java_director_exception_feature_Consts.GENERICPONGEXCP1.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_MyFooDirectorImpl.genericpong(java_director_exception_feature_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(2); fail("No exception thrown in genericpong(2)");}
|
||||
catch (NewCheckedException e) {
|
||||
failif( ! java_director_exception_feature_Consts.GENERICPONGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_MyFooDirectorImpl.genericpong(java_director_exception_feature_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(3); fail("No exception thrown in genericpong(3)");}
|
||||
catch (NewUncheckedException e) {
|
||||
failif( ! java_director_exception_feature_Consts.GENERICPONGEXCP3.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
StackTraceElement[] st = e.getStackTrace();
|
||||
failif( st.length != 5, "Stack length is only " + st.length);
|
||||
failif( ! st[0].toString().startsWith("java_director_exception_feature_MyFooDirectorImpl.genericpong(java_director_exception_feature_runme.java:"), "Incorrect top of stack: " + st[0]);
|
||||
}
|
||||
try { b.genericpong(4); fail("No exception thrown in genericpong(4)");}
|
||||
catch (RuntimeException e) {
|
||||
failif ( e.getClass() != RuntimeException.class, "Exception " + e + " is not exactly RumtimeException");
|
||||
failif( ! java_director_exception_feature_Consts.GENERICPONGEXCP4.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
failif ( e.getClass() != RuntimeException.class, "Exception " + e + " is not exactly RuntimeException");
|
||||
failif( ! "Unspecified DirectorException message".equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
%feature("director:except") MyNS::Foo::ping {
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear(); // clear java exception since mapping to c++ exception
|
||||
if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyJavaException1")) {
|
||||
throw 1;
|
||||
} else if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyJavaException2")) {
|
||||
|
|
@ -71,7 +70,6 @@
|
|||
%feature("director:except") MyNS::Foo::pong %{
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
$directorthrowshandlers
|
||||
throw ::MyNS::Unexpected(Swig::JavaExceptionMessage(jenv,$error).message());
|
||||
}
|
||||
|
|
@ -121,7 +119,10 @@
|
|||
%feature("director:except") MyNS::Foo::genericpong {
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
if (Swig::ExceptionMatches(jenv,$error,"UnconstructableException")) {
|
||||
// Purposefully test NULL
|
||||
throw Swig::DirectorException(jenv, NULL);
|
||||
}
|
||||
throw Swig::DirectorException(jenv,$error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
%feature("director:except") MyNS::Foo::ping {
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear(); // clear java exception since mapping to c++ exception
|
||||
if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyNS/MyJavaException1")) {
|
||||
throw 1;
|
||||
} else if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyNS/MyJavaException2")) {
|
||||
|
|
@ -78,7 +77,6 @@
|
|||
%feature("director:except") MyNS::Foo::pong %{
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
$directorthrowshandlers
|
||||
throw ::MyNS::Unexpected(Swig::JavaExceptionMessage(jenv,$error).message());
|
||||
}
|
||||
|
|
@ -128,7 +126,10 @@
|
|||
%feature("director:except") MyNS::Foo::genericpong {
|
||||
jthrowable $error = jenv->ExceptionOccurred();
|
||||
if ($error) {
|
||||
jenv->ExceptionClear();
|
||||
if (Swig::ExceptionMatches(jenv,$error,"java_director_exception_feature_nspace_UnconstructibleException")) {
|
||||
// Purposefully test NULL
|
||||
throw Swig::DirectorException(jenv, NULL);
|
||||
}
|
||||
throw Swig::DirectorException(jenv,$error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ namespace Swig {
|
|||
JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable) : message_(jenv, exceptionMessageFromThrowable(jenv, throwable)) {
|
||||
}
|
||||
|
||||
const char *message() const {
|
||||
return message_.c_str("Could not get exception message in JavaExceptionMessage");
|
||||
const char *message(const char *null_string = "Could not get exception message in JavaExceptionMessage") const {
|
||||
return message_.c_str(null_string);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -294,10 +294,11 @@ namespace Swig {
|
|||
public:
|
||||
|
||||
// Construct exception from a Java throwable
|
||||
DirectorException(JNIEnv *jenv, jthrowable throwable) : classname_(0), msg_(0) {
|
||||
DirectorException(JNIEnv *jenv, jthrowable throwable) : jenv_(jenv), throwable_(throwable), classname_(0), msg_(0) {
|
||||
|
||||
// Call Java method Object.getClass().getName() to obtain the throwable's class name (delimited by '/')
|
||||
if (throwable) {
|
||||
if (jenv && throwable) {
|
||||
jenv->ExceptionClear(); // Cannot invoke methods with any pending exceptions
|
||||
jclass throwclz = jenv->GetObjectClass(throwable);
|
||||
if (throwclz) {
|
||||
jclass clzclz = jenv->GetObjectClass(throwclz);
|
||||
|
|
@ -318,11 +319,11 @@ namespace Swig {
|
|||
}
|
||||
|
||||
JavaExceptionMessage exceptionmsg(jenv, throwable);
|
||||
msg_ = copystr(exceptionmsg.message());
|
||||
msg_ = copystr(exceptionmsg.message(0));
|
||||
}
|
||||
|
||||
// More general constructor for handling as a java.lang.RuntimeException
|
||||
DirectorException(const char *msg) : classname_(0), msg_(copystr(msg ? msg : "Unspecified DirectorException message")) {
|
||||
DirectorException(const char *msg) : jenv_(0), throwable_(0), classname_(0), msg_(msg ? copystr(msg) : 0) {
|
||||
}
|
||||
|
||||
~DirectorException() throw() {
|
||||
|
|
@ -331,28 +332,40 @@ namespace Swig {
|
|||
}
|
||||
|
||||
const char *what() const throw() {
|
||||
return msg_;
|
||||
return msg_ ? msg_ : "Unspecified DirectorException message";
|
||||
}
|
||||
|
||||
// Reconstruct and raise/throw the Java Exception that caused the DirectorException
|
||||
// Note that any error in the JNI exception handling results in a Java RuntimeException
|
||||
void raiseJavaException(JNIEnv *jenv) const {
|
||||
if (jenv) {
|
||||
jenv->ExceptionClear();
|
||||
if (jenv == jenv_ && throwable_) {
|
||||
// Throw original exception if not already pending
|
||||
jthrowable throwable = jenv->ExceptionOccurred();
|
||||
if (throwable && jenv->IsSameObject(throwable, throwable_) == JNI_FALSE) {
|
||||
jenv->ExceptionClear();
|
||||
throwable = 0;
|
||||
}
|
||||
if (!throwable)
|
||||
jenv->Throw(throwable_);
|
||||
} else {
|
||||
// Try and reconstruct original exception, but original stacktrace is not reconstructed
|
||||
jenv->ExceptionClear();
|
||||
|
||||
jmethodID ctorMethodID = 0;
|
||||
jclass throwableclass = 0;
|
||||
if (classname_) {
|
||||
throwableclass = jenv->FindClass(classname_);
|
||||
if (throwableclass)
|
||||
ctorMethodID = jenv->GetMethodID(throwableclass, "<init>", "(Ljava/lang/String;)V");
|
||||
}
|
||||
jmethodID ctorMethodID = 0;
|
||||
jclass throwableclass = 0;
|
||||
if (classname_) {
|
||||
throwableclass = jenv->FindClass(classname_);
|
||||
if (throwableclass)
|
||||
ctorMethodID = jenv->GetMethodID(throwableclass, "<init>", "(Ljava/lang/String;)V");
|
||||
}
|
||||
|
||||
if (ctorMethodID) {
|
||||
jenv->ThrowNew(throwableclass, what());
|
||||
} else {
|
||||
SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, what());
|
||||
}
|
||||
if (ctorMethodID) {
|
||||
jenv->ThrowNew(throwableclass, what());
|
||||
} else {
|
||||
SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,6 +393,8 @@ namespace Swig {
|
|||
return target;
|
||||
}
|
||||
|
||||
JNIEnv *jenv_;
|
||||
jthrowable throwable_;
|
||||
const char *classname_;
|
||||
const char *msg_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4463,8 +4463,8 @@ public:
|
|||
if (!directorexcept) {
|
||||
directorexcept = NewString("");
|
||||
Printf(directorexcept, "jthrowable $error = jenv->ExceptionOccurred();\n");
|
||||
Printf(directorexcept, "if ($error) {\n");
|
||||
Printf(directorexcept, " jenv->ExceptionClear();$directorthrowshandlers\n");
|
||||
Printf(directorexcept, "if ($error) {");
|
||||
Printf(directorexcept, "$directorthrowshandlers\n");
|
||||
Printf(directorexcept, " Swig::DirectorException::raise(jenv, $error);\n");
|
||||
Printf(directorexcept, "}\n");
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue