diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html index 69cdc4eba..664ccb7d2 100644 --- a/Doc/Manual/Java.html +++ b/Doc/Manual/Java.html @@ -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
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.
Because the default code generation maps any unhandled Java exceptions to
Swig::DirectorException, 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:
@@ -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
meth1, meth2 and meth3. 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 %catches feature.
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 Swig::DirectorException class provides enough information
diff --git a/Examples/test-suite/java/java_director_exception_feature_nspace_runme.java b/Examples/test-suite/java/java_director_exception_feature_nspace_runme.java
index ea7da5c1a..884b04c6e 100644
--- a/Examples/test-suite/java/java_director_exception_feature_nspace_runme.java
+++ b/Examples/test-suite/java/java_director_exception_feature_nspace_runme.java
@@ -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) {
diff --git a/Examples/test-suite/java/java_director_exception_feature_runme.java b/Examples/test-suite/java/java_director_exception_feature_runme.java
index 2e919c18a..d9763c992 100644
--- a/Examples/test-suite/java/java_director_exception_feature_runme.java
+++ b/Examples/test-suite/java/java_director_exception_feature_runme.java
@@ -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() + "'");
}
}
diff --git a/Examples/test-suite/java_director_exception_feature.i b/Examples/test-suite/java_director_exception_feature.i
index a0b3b7261..0cd555875 100644
--- a/Examples/test-suite/java_director_exception_feature.i
+++ b/Examples/test-suite/java_director_exception_feature.i
@@ -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);
}
}
diff --git a/Examples/test-suite/java_director_exception_feature_nspace.i b/Examples/test-suite/java_director_exception_feature_nspace.i
index 3111538fc..aa8c64cc9 100644
--- a/Examples/test-suite/java_director_exception_feature_nspace.i
+++ b/Examples/test-suite/java_director_exception_feature_nspace.i
@@ -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);
}
}
diff --git a/Lib/java/director.swg b/Lib/java/director.swg
index abde72286..e85ca376e 100644
--- a/Lib/java/director.swg
+++ b/Lib/java/director.swg
@@ -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, "", "(Ljava/lang/String;)V");
- }
+ jmethodID ctorMethodID = 0;
+ jclass throwableclass = 0;
+ if (classname_) {
+ throwableclass = jenv->FindClass(classname_);
+ if (throwableclass)
+ ctorMethodID = jenv->GetMethodID(throwableclass, "", "(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_;
};
diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx
index 68f1bb273..f759aaf5d 100644
--- a/Source/Modules/java.cxx
+++ b/Source/Modules/java.cxx
@@ -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 {