aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.current14
-rw-r--r--Doc/Manual/Java.html347
-rw-r--r--Doc/Manual/Warnings.html1
-rw-r--r--Examples/csharp/variables/example.c2
-rw-r--r--Examples/d/variables/example.c2
-rw-r--r--Examples/go/variables/example.c2
-rw-r--r--Examples/java/variables/example.c2
-rw-r--r--Examples/lua/variables/example.c2
-rw-r--r--Examples/octave/variables/example.c2
-rw-r--r--Examples/perl5/variables/example.c2
-rw-r--r--Examples/php/variables/example.c2
-rw-r--r--Examples/python/variables/example.c2
-rw-r--r--Examples/ruby/variables/example.c2
-rw-r--r--Examples/tcl/variables/example.c2
-rw-r--r--Examples/test-suite/director_exception.i23
-rw-r--r--Examples/test-suite/java/Makefile.in3
-rw-r--r--Examples/test-suite/java/java_director_exception_feature_nspace_runme.java150
-rw-r--r--Examples/test-suite/java/java_director_exception_feature_runme.java152
-rw-r--r--Examples/test-suite/java_director_exception_feature.i212
-rw-r--r--Examples/test-suite/java_director_exception_feature_nspace.i219
-rw-r--r--Lib/guile/guile_scm_run.swg15
-rw-r--r--Lib/guile/std_vector.i4
-rw-r--r--Lib/java/director.swg201
-rw-r--r--Lib/java/std_string.i4
-rw-r--r--Lib/python/pyinit.swg4
-rw-r--r--Lib/r/rrun.swg2
-rw-r--r--Lib/ruby/rubycontainer.swg1
-rw-r--r--Lib/ruby/rubyprimtypes.swg2
-rw-r--r--Lib/ruby/rubyrun.swg3
-rw-r--r--Source/Include/swigwarn.h1
-rw-r--r--Source/Modules/guile.cxx4
-rw-r--r--Source/Modules/java.cxx178
-rw-r--r--Source/Modules/php.cxx1
-rw-r--r--Source/Swig/stype.c1
34 files changed, 1479 insertions, 85 deletions
diff --git a/CHANGES.current b/CHANGES.current
index db0a9899f..0f964b114 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -5,6 +5,20 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 3.0.0 (in progress)
============================
+2013-11-05: wsfulton
+ [Java] Fix some corner cases for the $packagepath/$javaclassname special variable substitution.
+
+2013-11-05: wsfulton
+ [Java] Apply patch #91 from Marvin Greenberg - Add director:except feature for improved
+ exception handling in director methods for Java.
+
+2013-10-17: wsfulton
+ [R] Fix SF #1340 - Visual Studio compile error in C++ wrappers due to #include <exception>
+ within extern "C" block.
+
+2013-10-17: wsfulton
+ [Python] Fix SF #1345 - Missing #include <stddef.h> for offsetof when using -builtin.
+
2013-10-15: vadz
Allow using \l, \L, \u, \U and \E in the substitution part of %(regex:/pattern/subst/)
inside %rename to change the case of the text being replaced.
diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html
index f3d8a1684..08c80c83a 100644
--- a/Doc/Manual/Java.html
+++ b/Doc/Manual/Java.html
@@ -87,6 +87,7 @@
<li><a href="#Java_directors_example">Simple directors example</a>
<li><a href="#Java_directors_threading">Director threading issues</a>
<li><a href="#Java_directors_performance">Director performance tuning</a>
+<li><a href="#Java_exceptions_from_directors">Java Exceptions from Directors</a>
</ul>
<li><a href="#Java_allprotected">Accessing protected members</a>
<li><a href="#Java_common_customization">Common customization features</a>
@@ -3555,6 +3556,312 @@ However, if all director methods are expected to usually be overridden by Java s
The disadvantage is that invocation of director methods from C++ when Java doesn't actually override the method will require an additional call up into Java and back to C++. As such, this option is only useful when overrides are extremely common and instantiation is frequent enough that its performance is critical.
</p>
+<H3><a name="Java_exceptions_from_directors"></a>24.5.7 Java exceptions from directors</H3>
+
+<p>
+With directors routing method calls to Java, and proxies routing them
+to C++, the handling of exceptions is an important concern.
+The default behavior from SWIG 3.0
+onwards is to convert the thrown Java exception into a SWIG defined
+<code>DirectorException</code> C++ exception.
+SWIG 2.0 and earlier versions didn't provide any mechanism to handle the Java director method exceptions in C++.
+</p>
+
+<p>
+Converting Java exceptions into C++ exceptions can be done in two different ways using
+the <code>director:except</code> <a href="Customization.html#Customization_features">feature</a>.
+In the simplest approach, a code block is attached to each director method to
+handle the mapping of Java exceptions into C++ exceptions.
+</p>
+
+<div class="code">
+<pre>
+%feature("director:except") MyClass::method(int x) {
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
+ if ($error) {
+ jenv-&gt;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"))
+ throw MyCppException(Swig::JavaExceptionMessage(jenv, $error).message());
+ throw std::runtime_error("Unexpected exception thrown in MyClass::method");
+ }
+}
+
+class MyClass {
+ /** Throws either a std::out_of_range or MyCppException on error */
+ void method(int x);
+}
+</pre>
+</div>
+
+<p>
+This approach allows a flexible mapping of Java exceptions thrown by director methods into
+C++ exceptions expected by a C++ caller. There
+need not be any C++ <em>exception specifications</em> on the C++ method. The
+utility function <code>Swig::ExceptionMatches</code>
+and class <code>Swig::JavaExceptionMessage</code> are provided to simplify
+writing code for wrappers that use the <code>director:except</code> feature. The
+function <code>Swig::ExceptionMatches</code> matches the type of the
+<code>jthrowable</code> thrown against a <b>fully qualified</b> JNI style class
+name, such as <code>"java/lang/IOError"</code>. If the throwable class is the same
+type, or derives from the given type, <code>Swig::ExceptionMatches</code> will return true. Care must be taken to
+provide the correct fully qualified name, since for wrapped exceptions the
+generated proxy class will have additional package qualification, depending on
+the '-package' argument and use of the <a href="#Java_namespaces">nspace
+ feature</a>. The special variable <code>$error</code> is expanded by SWIG into a unique variable name and
+should be used for the
+assignment of the exception that occurred. The special variable <code>$packagepath</code> is
+replaced by the outer package provided for SWIG generation by the -package
+option. The utility class <code>Swig::JavaExceptionMessage</code> is a holder
+providing access to the message from the thrown Java exception.
+The <code>message()</code> method returns the exception message as a <code>const char *</code>,
+which is only valid during the lifetime of the holder. Any code using this message
+needs to copy it, for example into a std::string or a newly constructed C++ exception.
+</p>
+
+<p>
+Using the above approach to
+write handlers for a large number of methods will require
+repetitive duplication of the <code>director:except</code> feature code.
+To mitigate this, an alternative approach is provided via typemaps in a
+fashion analagous to
+the <a href="Typemaps.html#throws_typemap">"throws" typemap.</a> The
+"throws" typemap provides an approach to automatically map all the C++
+exceptions listed in a method's defined exceptions (either from
+a C++ <em>exception specification</em> or a <code>%catches</code>
+feature) into Java exceptions.
+The "directorthrows" typemap provides the inverse mapping and should contain
+code to convert a suitably matching Java exception into a C++ exception.
+The example below converts a Java <code>java.lang.IndexOutOfBoundsException</code> exception
+to the typemap's type, that is <code>std::out_of_range</code>:
+
+<div class="code">
+<pre>
+%typemap(directorthrows) std::out_of_range %{
+ if (Swig::ExceptionMatches(jenv, $error, "java/lang/IndexOutOfBoundsException")) {
+ throw std::out_of_range(Swig::JavaExceptionMessage(jenv, $error).message());
+ }
+%}
+</pre>
+</div>
+
+<p>
+The "directorthrows" typemap is then used in conjunction with the
+<code>director:except</code> feature if the <code>$directorthrowshandlers</code> special variable
+is used in the feature code. Consider the following, which also happens to be the default:
+</p>
+
+<div class="code">
+<pre>
+%feature("director:except") %{
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
+ if ($error) {
+ jenv-&gt;ExceptionClear();
+ $directorthrowshandlers
+ throw Swig::DirectorException(jenv, $error);
+ }
+%}
+</pre>
+</div>
+
+<p>The code generated using the <code>director:except</code> feature
+replaces the <code>$directorthrowshandlers</code> special variable with the code in
+the "directorthrows" typemaps, for each and every exception defined for the method.
+The possible exceptions can be defined either with a C++ exception
+specification or <code>%catches</code> as described for the
+<a href="Typemaps.html#throws_typemap">"throws" typemap</a>.
+</p>
+
+<p>
+Consider the following director method:
+</p>
+
+<div class="code">
+<pre>
+ ...
+ virtual void doSomething(int index) throw (std::out_of_range);
+ ...
+</pre>
+</div>
+
+<p>
+When combined with the default <code>director:except</code> feature and the "directorthrows" typemap above,
+the resulting code generated in the director method after calling up to Java will be:
+</p>
+
+<div class="code">
+<pre>
+jthrowable swigerror = jenv-&gt;ExceptionOccurred();
+if (swigerror) {
+ jenv-&gt;ExceptionClear();
+ if (Swig::ExceptionMatches(jenv, swigerror, "java/lang/IndexOutOfBoundsException")) {
+ throw std::out_of_range(Swig::JavaExceptionMessage(jenv, swigerror).message());
+ }
+
+ throw Swig::DirectorException(jenv, swigerror);
+}
+</pre>
+</div>
+
+<p><em>
+Note: Beware of using exception specifications as the SWIG director methods
+will be generated with the same exception specifications and if the
+director method throws an exception that is not specified it is likely
+to terminate your program. See the C++ standard for more details.
+Using the %catches feature instead to define the handled exceptions does not suffer
+this potential fate.
+</em></p>
+
+<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:
+
+<div class="code">
+<pre>
+%feature("director:except") %{
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
+ if ($error) {
+ jenv-&gt;ExceptionClear();
+ $directorthrowshandlers
+ return $null; // exception is ignored
+ }
+%}
+</pre>
+</div>
+</p>
+
+<p>Alternatively an exception compatible with the existing director
+method exception specifications can be thrown. Assuming that all
+methods allow std::runtime_error to be thrown,
+the <code>return&nbsp;$null;</code> could be changed to:
+</p>
+
+<div class="code">
+<pre>
+ throw std::runtime_error(Swig::JavaExceptionMessage(jenv, $error).message());
+</pre>
+</div>
+
+<p>In more complex situations, a separate <code>director:except</code> feature
+may need to be attached to specific methods.
+</p>
+
+<p>Below is a complete example demonstrating the use
+of the "directorthrows" typemaps. In this example, a
+generic "directorthrows" typemap is appropriate for all three exceptions - all
+take single string constructors. If the exceptions had different constructors,
+it would be neccessary to have separate typemaps for each exception type.
+
+
+<!-- All the DEFINE_ and DECLARE_EXCEPTIONS CAN BE OMITTED to make
+ this more succinct. They are included to make this a complete
+ example interface that could be generated and built. -->
+<div class="code">
+<pre>
+%module(directors="1") example
+
+%{
+ #include &lt;string&gt;
+ #include &lt;stdexcept&gt;
+%}
+
+// Define exceptions in header section using std::runtime_error
+%define DEFINE_EXCEPTION(NAME)
+%{
+ namespace MyNS {
+ struct NAME : public std::runtime_error { NAME(const std::string &amp;what) : runtime_error(what) {} };
+ }
+%}
+%enddef
+
+// Expose C++ exceptions as Java Exceptions by changing the Java base class and providing a getMessage()
+%define DECLARE_EXCEPTION(NAME)
+%typemap(javabase) MyNS::NAME "java.lang.Exception";
+%rename(getMessage) MyNS::NAME::what;
+namespace MyNS {
+ struct NAME {
+ NAME(const std::string&amp; what);
+ const char * what();
+ };
+}
+%enddef
+
+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"))
+ throw $1_type(Swig::JavaExceptionMessage(jenv, $error).message());
+%}
+
+DECLARE_EXCEPTION(ExceptionA)
+DECLARE_EXCEPTION(ExceptionB)
+DECLARE_EXCEPTION(Unexpected)
+
+%catches(MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected) MyClass::meth2();
+
+%inline {
+ class MyClass {
+ public:
+ virtual void meth1(int x) throw(MyNS::ExceptionA, MyNS::ExceptionB) = 0;
+ virtual void meth2() = 0; /* throws MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected */
+ virtual void meth3(float x) throw(MyNS::Unexpected) = 0;
+ virtual ~MyClass() {}
+ };
+}
+</pre>
+</div>
+
+<p>
+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
+the exception specification or <code>%catches</code> feature.
+</p>
+
+<p>Note that the "directorthrows" typemaps are important
+only if it is important for the the exceptions passed through the C++
+layer 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
+to reconstruct the original exception. In this case removing the
+<code>$directorthrowshandlers</code> special variable from the
+default <code>director:except</code> feature and simply always
+throwing a <code>Swig::DirectorException</code> will achieve the desired result.
+Along with this a generic exception feature is added to convert any
+caught <code>Swig::DirectorException</code>s back into the underlying
+Java exceptions via the <code>Swig::DirectorException::raiseJavaException</code> method,
+as demonstrated with <code>%javaexception</code> below:
+</p>
+
+<div class="code">
+<pre>
+%javaexception("Exception") MyClass::myMethod %{
+ try {
+ $action
+ } catch (Swig::DirectorException &amp;e) {
+ // raise/throw the Java exception that originally caused the DirectorException
+ e.raiseJavaException(jenv);
+ return $null;
+ }
+%}
+</pre>
+</div>
+
+<p>
+See the <a href="#Java_exception_handling">Exception handling with %exception and %javaexception</a>
+section for more on converting C++ exceptions to Java exceptions.
+</p>
<H2><a name="Java_allprotected"></a>24.6 Accessing protected members</H2>
@@ -5367,7 +5674,7 @@ can be wrapped with the Java equivalent, that is, static inner proxy classes.
</p>
<p>
-<b><tt>$jniinput, $javacall and $packagepath</tt></b><br>
+<b><tt>$error, $jniinput, $javacall and $packagepath</tt></b><br>
These special variables are used in the directors typemaps. See <a href="#Java_directors_typemaps">Director specific typemaps</a> for details.
</p>
@@ -5701,6 +6008,10 @@ is the package name passed from the SWIG command line and <code>$javaclassname</
If the <tt>-package</tt> commandline option is not used to specify the package, then '$packagepath/' will be removed from the resulting output JNI field descriptor.
<b>Do not forget the terminating ';' for JNI field descriptors starting with 'L'.</b>
If the ';' is left out, Java will generate a "method not found" runtime error.
+Note that the <code>$packagepath</code> substitution always uses the path separator '/' when expanded.
+The <code>$javaclassname</code> expansion can be confusing as it is normally expanded using the '.' separator.
+However, <code>$javaclassname</code> is expanded using the path separator '/' in typemap's "descriptor" attribute
+as well as in the "directorthrows" typemap.
</p>
</div>
@@ -5796,6 +6107,40 @@ The target method is the method in the Java proxy class which overrides the virt
</div>
+<p><tt>%typemap(directorthrows)</tt></p>
+<div class="indent">
+
+<p>
+Conversion of Java exceptions to C++ exceptions in director method's exception handling.
+This typemap is expected to test the <tt>$error</tt> special variable for a matching Java exception
+and if successful convert and throw it into a C++ exception given by the typemap's type.
+The <code>$error</code> special variable is of type <code>jthrowable</code> and is
+substituted with a unique variable name in the generated code.
+</p>
+
+<p>
+The example below converts a Java <code>java.lang.IndexOutOfBoundsException</code> exception
+to the typemap's type, that is <code>std::out_of_range</code>:
+</p>
+
+<div class="code">
+<pre>
+%typemap(directorthrows) std::out_of_range %{
+ if (Swig::ExceptionMatches(jenv, $error, "java/lang/IndexOutOfBoundsException")) {
+ throw std::out_of_range(Swig::JavaExceptionMessage(jenv, $error).message());
+ }
+%}
+</pre>
+</div>
+
+<p>
+The utility function <code>Swig::ExceptionMatches</code>
+and class <code>Swig::JavaExceptionMessage</code> are helpers available when using directors and are described
+in the <a href="#Java_exceptions_from_directors">Java Exceptions from Directors</a> section.
+</p>
+
+</div>
+
<p><tt>%typemap(javapackage)</tt></p>
<div class="indent">
diff --git a/Doc/Manual/Warnings.html b/Doc/Manual/Warnings.html
index aac415952..e0debe41c 100644
--- a/Doc/Manual/Warnings.html
+++ b/Doc/Manual/Warnings.html
@@ -499,6 +499,7 @@ example.i(4) : Syntax error in input.
<li>474. Method <em>method</em> usage of the optimal attribute ignored in the out typemap as the following cannot be used to generate optimal code: <em>code</em>
<li>475. Multiple calls to <em>method</em> might be generated due to optimal attribute usage in the out typemap.
<li>476. Initialization using std::initializer_list.
+<li>477. No directorthrows typemap defined for <em>type</em>
</ul>
diff --git a/Examples/csharp/variables/example.c b/Examples/csharp/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/csharp/variables/example.c
+++ b/Examples/csharp/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/d/variables/example.c b/Examples/d/variables/example.c
index 1bf9c120f..3b4e9f346 100644
--- a/Examples/d/variables/example.c
+++ b/Examples/d/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/go/variables/example.c b/Examples/go/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/go/variables/example.c
+++ b/Examples/go/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/java/variables/example.c b/Examples/java/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/java/variables/example.c
+++ b/Examples/java/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/lua/variables/example.c b/Examples/lua/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/lua/variables/example.c
+++ b/Examples/lua/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/octave/variables/example.c b/Examples/octave/variables/example.c
index 15dcc1b8e..e2b72e0ea 100644
--- a/Examples/octave/variables/example.c
+++ b/Examples/octave/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/perl5/variables/example.c b/Examples/perl5/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/perl5/variables/example.c
+++ b/Examples/perl5/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/php/variables/example.c b/Examples/php/variables/example.c
index 3114c7c5f..b21dee32d 100644
--- a/Examples/php/variables/example.c
+++ b/Examples/php/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %c%c%c%c%c\n", name[0],name[1],name[2],name[3],name[4]);
printf("ptptr = %p %s\n", ptptr, Point_print( ptptr ) );
diff --git a/Examples/python/variables/example.c b/Examples/python/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/python/variables/example.c
+++ b/Examples/python/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/ruby/variables/example.c b/Examples/ruby/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/ruby/variables/example.c
+++ b/Examples/ruby/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/tcl/variables/example.c b/Examples/tcl/variables/example.c
index aa4ffe9b3..05e17c8c5 100644
--- a/Examples/tcl/variables/example.c
+++ b/Examples/tcl/variables/example.c
@@ -51,7 +51,7 @@ void print_vars() {
printf("dvar = %g\n", dvar);
printf("cvar = %c\n", cvar);
printf("strvar = %s\n", strvar ? strvar : "(null)");
- printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)");
+ printf("cstrvar = %s\n", cstrvar);
printf("iptrvar = %p\n", iptrvar);
printf("name = %s\n", name);
printf("ptptr = %p (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0);
diff --git a/Examples/test-suite/director_exception.i b/Examples/test-suite/director_exception.i
index de0ef3343..3fd3e563c 100644
--- a/Examples/test-suite/director_exception.i
+++ b/Examples/test-suite/director_exception.i
@@ -41,6 +41,29 @@ class DirectorMethodException: public Swig::DirectorException {};
#endif
+#ifdef SWIGJAVA
+
+// Default for director exception warns about unmapped exceptions now in java
+// Suppress warnings for this older test
+// %warnfilter(476) Bar;
+
+// Default for java is to throw Swig::DirectorException if no
+// direct:except feature. Since methods below have exception specification
+// cannot throw director exception.
+
+// Change back to old 2.0 default behavior
+
+%feature("director:except") {
+ jthrowable $error = jenv->ExceptionOccurred();
+ if ($error) {
+ // Dont clear exception, still be active when return to java execution
+ // Essentially ignore exception occurred -- old behavior.
+ return $null;
+ }
+}
+
+#endif
+
#ifdef SWIGRUBY
%feature("director:except") {
diff --git a/Examples/test-suite/java/Makefile.in b/Examples/test-suite/java/Makefile.in
index e4f3c6b58..1bd4b0261 100644
--- a/Examples/test-suite/java/Makefile.in
+++ b/Examples/test-suite/java/Makefile.in
@@ -24,6 +24,8 @@ CPP_TEST_CASES = \
java_constants \
java_director \
java_director_assumeoverride \
+ java_director_exception_feature \
+ java_director_exception_feature_nspace \
java_enums \
java_jnitypes \
java_lib_arrays_dimensionless \
@@ -46,6 +48,7 @@ SWIGOPT += $(JAVA_PACKAGEOPT)
# Custom tests - tests with additional commandline options
java_nspacewithoutpackage.%: JAVA_PACKAGEOPT =
+java_director_exception_feature_nspace.%: JAVA_PACKAGE = $*Package
nspace.%: JAVA_PACKAGE = $*Package
nspace_extend.%: JAVA_PACKAGE = $*Package
director_nspace.%: JAVA_PACKAGE = $*Package
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
new file mode 100644
index 000000000..ea7da5c1a
--- /dev/null
+++ b/Examples/test-suite/java/java_director_exception_feature_nspace_runme.java
@@ -0,0 +1,150 @@
+import java_director_exception_feature_nspacePackage.*;
+import java_director_exception_feature_nspacePackage.MyNS.*;
+
+class java_director_exception_feature_nspace_Consts {
+ public static final String PINGEXCP1 = "Ping MyJavaException1"; // should get translated through an int on ping
+ public static final String PINGEXCP2 = "Ping MyJavaException2";
+
+ public static final String PONGEXCP1 = "Pong MyJavaException1";
+ public static final String PONGEXCP2 = "Pong MyJavaException2";
+ public static final String PONGUNEXPECTED = "Pong MyJavaUnexpected";
+ public static final String TRANSLATED_NPE = "Pong Translated NPE";
+
+ public static final String GENERICPONGEXCP1 = "GenericPong Wrapped MyJavaException1";
+ public static final String GENERICPONGEXCP2 = "GenericPong New Checked Exception";
+ public static final String GENERICPONGEXCP3 = "GenericPong New Unchecked Exception";
+ public static final String GENERICPONGEXCP4 = "GenericPong New Exception Without String ctor";
+}
+
+// an exception not mentioned or wrapped by the swig interface,
+// to reconstruct using generic DirectorException handling
+class java_director_exception_feature_nspace_NewCheckedException extends Exception {
+ public java_director_exception_feature_nspace_NewCheckedException(String s) {
+ super(s);
+ }
+}
+
+// an exception not mentioned or wrapped by the swig interface,
+// to reconstruct using generic DirectorException handling
+class java_director_exception_feature_nspace_NewUncheckedException extends RuntimeException {
+ public java_director_exception_feature_nspace_NewUncheckedException(String s) {
+ super(s);
+ }
+}
+
+// an exception not constructible from a string,
+// to test DirectorException fallback reconstruction
+class java_director_exception_feature_nspace_UnconstructibleException extends Exception {
+ private int extrastate;
+ public java_director_exception_feature_nspace_UnconstructibleException(int a, String s) {
+ super(s);
+ extrastate = a;
+ }
+}
+
+class java_director_exception_feature_nspace_MyFooDirectorImpl extends Foo {
+
+ public java_director_exception_feature_nspace_MyFooDirectorImpl() { };
+
+ @Override
+ public String ping(int excp) throws MyJavaException1, MyJavaException2 {
+ if (excp == 1) throw new MyJavaException1(java_director_exception_feature_nspace_Consts.PINGEXCP1);
+ if (excp == 2) throw new MyJavaException2(java_director_exception_feature_nspace_Consts.PINGEXCP2);
+ return "Ping director returned";
+ }
+ @Override
+ public String pong(int excp) throws MyJavaException1, MyJavaException2, MyJavaUnexpected {
+ if (excp == 1) throw new MyJavaException1(java_director_exception_feature_nspace_Consts.PONGEXCP1);
+ if (excp == 2) throw new MyJavaException2(java_director_exception_feature_nspace_Consts.PONGEXCP2);
+ if (excp == 3) throw new MyJavaUnexpected(java_director_exception_feature_nspace_Consts.PONGUNEXPECTED);
+ if (excp == 4) throw new java.lang.NullPointerException(java_director_exception_feature_nspace_Consts.TRANSLATED_NPE); // should be translated to ::Unexpected
+ return "Pong director returned";
+ }
+
+ @Override
+ public String genericpong(int excp) throws MyJavaException1, java_director_exception_feature_nspace_NewCheckedException, java_director_exception_feature_nspace_UnconstructibleException {
+ if (excp == 1)
+ throw new MyJavaException1(java_director_exception_feature_nspace_Consts.GENERICPONGEXCP1);
+ if (excp == 2)
+ throw new java_director_exception_feature_nspace_NewCheckedException(java_director_exception_feature_nspace_Consts.GENERICPONGEXCP2);
+ if (excp == 3)
+ throw new java_director_exception_feature_nspace_NewUncheckedException(java_director_exception_feature_nspace_Consts.GENERICPONGEXCP3);
+ if (excp == 4)
+ throw new java_director_exception_feature_nspace_UnconstructibleException(1, java_director_exception_feature_nspace_Consts.GENERICPONGEXCP4);
+ return "GenericPong director returned";
+ }
+}
+
+public class java_director_exception_feature_nspace_runme {
+
+ static {
+ try {
+ System.loadLibrary("java_director_exception_feature_nspace");
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
+ System.exit(1);
+ }
+ }
+
+ public static void fail(String msg) {
+ System.err.println(msg); System.exit(1);
+ }
+ public static void failif(boolean cond, String msg) {
+ if (cond) fail(msg);
+ }
+
+
+ public static void main(String argv[]) {
+
+ Bar b = new Bar(new java_director_exception_feature_nspace_MyFooDirectorImpl());
+ try {
+
+ try { b.ping(0); } catch (Exception e)
+ { fail("Exception should not have been thrown: " + e + " from ping(0)"); }
+ try { b.ping(1); fail("No exception thrown in ping(1)"); } catch (MyJavaException1 e)
+ // Should say "Threw some integer", see java_director_exception_feature.i Foo::ping throws a "1"
+ { failif( ! "Threw some integer".equals(e.getMessage()), "Ping exception not translated through int: '" + e.getMessage() + "'"); }
+ try { b.ping(2); fail("No exception thrown in ping(2)"); } catch (MyJavaException2 e)
+ { failif( ! java_director_exception_feature_nspace_Consts.PINGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+
+ try { b.pong(0); } catch (Exception e)
+ { fail("Exception should not have been thrown: " + e + " from pong(0)"); }
+ try { b.pong(1); fail("No exception thrown in pong(1)"); } catch (MyJavaException1 e)
+ { failif( ! java_director_exception_feature_nspace_Consts.PONGEXCP1.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(2); fail("No exception thrown in pong(2)");} catch (MyJavaException2 e)
+ { failif( ! java_director_exception_feature_nspace_Consts.PONGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(3); fail("No exception thrown in pong(3)");} catch (MyJavaUnexpected e)
+ { failif( ! java_director_exception_feature_nspace_Consts.PONGUNEXPECTED.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(4); fail("No exception thrown in pong(4)"); } catch (MyJavaUnexpected e)
+ { failif( ! java_director_exception_feature_nspace_Consts.TRANSLATED_NPE.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+
+
+ try { b.genericpong(0); }
+ catch (Exception e) {
+ fail("Exception should not have been thrown: " + e + " from genericpong(0)");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("Unexpected exception thrown or exception not mapped properly");
+ }
+
+ }
+}
diff --git a/Examples/test-suite/java/java_director_exception_feature_runme.java b/Examples/test-suite/java/java_director_exception_feature_runme.java
new file mode 100644
index 000000000..2e919c18a
--- /dev/null
+++ b/Examples/test-suite/java/java_director_exception_feature_runme.java
@@ -0,0 +1,152 @@
+
+import java_director_exception_feature.*;
+
+class java_director_exception_feature_Consts {
+ public static final String PINGEXCP1 = "Ping MyJavaException1"; // should get translated through an int on ping
+ public static final String PINGEXCP2 = "Ping MyJavaException2";
+
+ public static final String PONGEXCP1 = "Pong MyJavaException1";
+ public static final String PONGEXCP2 = "Pong MyJavaException2";
+ public static final String PONGUNEXPECTED = "Pong MyJavaUnexpected";
+ public static final String TRANSLATED_NPE = "Pong Translated NPE";
+
+ public static final String GENERICPONGEXCP1 = "GenericPong Wrapped MyJavaException1";
+ public static final String GENERICPONGEXCP2 = "GenericPong New Checked Exception";
+ public static final String GENERICPONGEXCP3 = "GenericPong New Unchecked Exception";
+ public static final String GENERICPONGEXCP4 = "GenericPong New Exception Without String ctor";
+
+}
+
+// an exception not mentioned or wrapped by the swig interface,
+// to reconstruct using generic DirectorException handling
+class NewCheckedException extends Exception {
+ public NewCheckedException(String s) {
+ super(s);
+ }
+}
+
+// an exception not mentioned or wrapped by the swig interface,
+// to reconstruct using generic DirectorException handling
+class NewUncheckedException extends RuntimeException {
+ public NewUncheckedException(String s) {
+ super(s);
+ }
+}
+
+// an exception not constructable from a string,
+// to test DirectorException fallback reconstruction
+class UnconstructableException extends Exception {
+ private int extrastate;
+ public UnconstructableException(int a, String s) {
+ super(s);
+ extrastate = a;
+ }
+}
+
+class java_director_exception_feature_MyFooDirectorImpl extends Foo {
+
+ public java_director_exception_feature_MyFooDirectorImpl() { };
+
+ @Override
+ public String ping(int excp) throws MyJavaException1, MyJavaException2 {
+ if (excp == 1) throw new MyJavaException1(java_director_exception_feature_Consts.PINGEXCP1);
+ if (excp == 2) throw new MyJavaException2(java_director_exception_feature_Consts.PINGEXCP2);
+ return "Ping director returned";
+ }
+ @Override
+ public String pong(int excp) throws MyJavaException1, MyJavaException2, MyJavaUnexpected {
+ if (excp == 1) throw new MyJavaException1(java_director_exception_feature_Consts.PONGEXCP1);
+ if (excp == 2) throw new MyJavaException2(java_director_exception_feature_Consts.PONGEXCP2);
+ if (excp == 3) throw new MyJavaUnexpected(java_director_exception_feature_Consts.PONGUNEXPECTED);
+ if (excp == 4) throw new java.lang.NullPointerException(java_director_exception_feature_Consts.TRANSLATED_NPE); // should be translated to ::Unexpected
+ return "Pong director returned";
+ }
+
+ @Override
+ public String genericpong(int excp) throws MyJavaException1, NewCheckedException, UnconstructableException {
+ if (excp == 1)
+ throw new MyJavaException1(java_director_exception_feature_Consts.GENERICPONGEXCP1);
+ if (excp == 2)
+ throw new NewCheckedException(java_director_exception_feature_Consts.GENERICPONGEXCP2);
+ if (excp == 3)
+ throw new NewUncheckedException(java_director_exception_feature_Consts.GENERICPONGEXCP3);
+ if (excp == 4)
+ throw new UnconstructableException(1, java_director_exception_feature_Consts.GENERICPONGEXCP4);
+ return "GenericPong director returned";
+ }
+}
+
+public class java_director_exception_feature_runme {
+
+ static {
+ try {
+ System.loadLibrary("java_director_exception_feature");
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
+ System.exit(1);
+ }
+ }
+
+ public static void fail(String msg) {
+ System.err.println(msg); System.exit(1);
+ }
+ public static void failif(boolean cond, String msg) {
+ if (cond) fail(msg);
+ }
+
+
+ public static void main(String argv[]) {
+
+ Bar b = new Bar(new java_director_exception_feature_MyFooDirectorImpl());
+ try {
+
+ try { b.ping(0); } catch (Exception e)
+ { fail("Exception should not have been thrown: " + e + " from ping(0)"); }
+ try { b.ping(1); fail("No exception thrown in ping(1)"); } catch (MyJavaException1 e)
+ // Should say "Threw some integer", see java_director_exception_feature.i Foo::ping throws a "1"
+ { failif( ! "Threw some integer".equals(e.getMessage()), "Ping exception not translated through int: '" + e.getMessage() + "'"); }
+ try { b.ping(2); fail("No exception thrown in ping(2)"); } catch (MyJavaException2 e)
+ { failif( ! java_director_exception_feature_Consts.PINGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+
+ try { b.pong(0); } catch (Exception e)
+ { fail("Exception should not have been thrown: " + e + " from pong(0)"); }
+ try { b.pong(1); fail("No exception thrown in pong(1)"); } catch (MyJavaException1 e)
+ { failif( ! java_director_exception_feature_Consts.PONGEXCP1.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(2); fail("No exception thrown in pong(2)");} catch (MyJavaException2 e)
+ { failif( ! java_director_exception_feature_Consts.PONGEXCP2.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(3); fail("No exception thrown in pong(3)");} catch (MyJavaUnexpected e)
+ { failif( ! java_director_exception_feature_Consts.PONGUNEXPECTED.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+ try { b.pong(4); fail("No exception thrown in pong(4)"); } catch (MyJavaUnexpected e)
+ { failif( ! java_director_exception_feature_Consts.TRANSLATED_NPE.equals(e.getMessage()), "Expected exception has unexpected message: '" + e.getMessage() + "'"); }
+
+
+ try { b.genericpong(0); }
+ catch (Exception e) {
+ fail("Exception should not have been thrown: " + e + " from genericpong(0)");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+ 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() + "'");
+ }
+
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ fail("Unexpected exception thrown or exception not mapped properly");
+ }
+
+ }
+}
diff --git a/Examples/test-suite/java_director_exception_feature.i b/Examples/test-suite/java_director_exception_feature.i
new file mode 100644
index 000000000..1552454dc
--- /dev/null
+++ b/Examples/test-suite/java_director_exception_feature.i
@@ -0,0 +1,212 @@
+%module(directors="1") java_director_exception_feature
+
+%include <std_except.i>
+
+%warnfilter(SWIGWARN_TYPEMAP_DIRECTORTHROWS_UNDEF) MyNS::Foo::directorthrows_warning;
+
+%{
+#if defined(_MSC_VER)
+ #pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
+#endif
+
+#include <string>
+%}
+
+%include <std_string.i>
+
+// DEFINE exceptions in header section using std::runtime_error
+%{
+ #include <exception>
+ #include <iostream>
+
+ namespace MyNS {
+
+ struct Exception1 : public std::runtime_error {
+ Exception1(const std::string& what):runtime_error(what) {}
+ };
+ struct Exception2 : public std::runtime_error {
+ Exception2(const std::string& what):runtime_error(what) {}
+ };
+ struct Unexpected : public std::runtime_error {
+ Unexpected(const std::string& what):runtime_error(what) {}
+ };
+
+ }
+
+%}
+
+// Add an explicit handler for Foo::ping, mapping one java exception back to an 'int'
+%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")) {
+ std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
+ throw MyNS::Exception2(msg);
+ } else {
+ std::cerr << "Test failed, unexpected exception thrown: " <<
+ Swig::JavaExceptionMessage(jenv,$error).message() << std::endl;
+ throw std::runtime_error("unexpected exception in Foo::ping");
+ }
+ }
+}
+
+// Use default handler on Foo::pong, with directorthrows typemaps
+
+// directorthrows typemaps for java->c++ conversions
+%typemap(directorthrows) MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected %{
+ if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname")) {
+ std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
+ throw $1_type(msg);
+ }
+%}
+
+// Override the director:except feature so exception specification is not violated
+// (Cannot use built-in default of throw DirectorException)
+%feature("director:except") MyNS::Foo::pong %{
+ jthrowable $error = jenv->ExceptionOccurred();
+ if ($error) {
+ jenv->ExceptionClear();
+ $directorthrowshandlers
+ throw ::MyNS::Unexpected(Swig::JavaExceptionMessage(jenv,$error).message());
+ }
+%}
+
+// TODO 'throws' typemap emitted by emit_action (emit.cxx) has no way
+// to get access to language specific special variables like
+// $javaclassname or $packagepath ("java_director_exception_feature" here)
+
+// throws typemaps for c++->java exception conversions
+%typemap(throws,throws="MyJavaException1") MyNS::Exception1 %{
+ jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException1");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+%typemap(throws,throws="MyJavaException1") int %{
+ jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException1");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, "Threw some integer");
+ }
+ return $null;
+%}
+
+%typemap(throws,throws="MyJavaException2") MyNS::Exception2 %{
+ jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException2");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+%typemap(throws,throws="MyJavaUnexpected") MyNS::Unexpected %{
+ jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaUnexpected");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+// Use generic exception translation approach like python, ruby
+
+%feature("director:except") MyNS::Foo::genericpong {
+ jthrowable $error = jenv->ExceptionOccurred();
+ if ($error) {
+ jenv->ExceptionClear();
+ throw Swig::DirectorException(jenv,$error);
+ }
+}
+
+// %exception with throws attribute. Need throws attribute for checked exceptions
+%feature ("except",throws="Exception") MyNS::Foo::genericpong %{
+%}
+
+%feature ("except",throws="Exception") MyNS::Bar::genericpong %{
+ try { $action }
+ catch (Swig::DirectorException & direxcp) {
+ direxcp.raiseJavaException(jenv); // jenv always available in JNI code
+ return $null;
+ }
+%}
+
+
+
+%feature("director") Foo;
+
+// Rename exceptions on java side to make translation of exceptions more clear
+%rename(MyJavaException1) MyNS::Exception1;
+%rename(MyJavaException2) MyNS::Exception2;
+%rename(MyJavaUnexpected) MyNS::Unexpected;
+
+%typemap(javabase) ::MyNS::Exception1,::MyNS::Exception2,::MyNS::Unexpected "java.lang.Exception";
+%rename(getMessage) what() const; // Rename all what() methods
+
+namespace MyNS {
+
+ struct Exception1 {
+ Exception1(const std::string& what);
+ const char * what() const;
+ };
+ struct Exception2 {
+ Exception2(const std::string& what);
+ const char * what() const;
+ };
+ struct Unexpected {
+ Unexpected(const std::string& what);
+ const char * what() const;
+ };
+
+}
+// In general it is better to use %catches instead of an exception specification on the method
+// since violating an exception specification calls terminate() preventing catch-all behavior
+// like throwing std::runtime_error. But an exception specification must be used if the
+// actual interface being wrapped does use them.
+%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Foo::pong;
+%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Bar::pong;
+
+%inline %{
+
+namespace MyNS {
+
+class Foo {
+public:
+ virtual ~Foo() {}
+ // ping java implementation throws a java Exception1 or an Exception2 if excp is 1 or 2.
+ // pong java implementation throws Exception1,Exception2,Unexpected,NullPointerException for 1,2,3,4
+ virtual std::string ping(int excp) throw(int,MyNS::Exception2) = 0;
+ virtual std::string pong(int excp) /* throws MyNS::Exception1 MyNS::Exception2 MyNS::Unexpected) */ = 0;
+ virtual std::string genericpong(int excp) /* unspecified throws - exception is always DirectorException in C++, translated back to whatever thrown in java */ = 0;
+ virtual std::string directorthrows_warning(int excp) throw(double) {}
+};
+
+// Make a bar from a foo, so a call to Java Bar
+// goes Java Bar -> C++ Bar -> C++ Foo -> Java Foo Director
+
+class Bar {
+public:
+ Bar(Foo* d) { delegate=d; }
+ virtual std::string ping(int excp) throw(int,MyNS::Exception2)
+ {
+ return delegate->ping(excp);
+ }
+
+ virtual std::string pong(int excp) /* throws MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected */
+ {
+ return delegate->pong(excp);
+ }
+
+ virtual std::string genericpong(int excp)
+ {
+ return delegate->genericpong(excp);
+ }
+
+private:
+ Foo * delegate;
+};
+
+}
+%}
diff --git a/Examples/test-suite/java_director_exception_feature_nspace.i b/Examples/test-suite/java_director_exception_feature_nspace.i
new file mode 100644
index 000000000..aea362905
--- /dev/null
+++ b/Examples/test-suite/java_director_exception_feature_nspace.i
@@ -0,0 +1,219 @@
+%module(directors="1") java_director_exception_feature_nspace
+
+%include <std_except.i>
+
+%nspace; // turn namespace feature on for everything.
+
+#define PACKAGEDOT "java_director_exception_feature_nspacePackage."
+#define PACKAGESLASH "java_director_exception_feature_nspacePackage/"
+%{
+#define PACKAGEDOT "java_director_exception_feature_nspacePackage."
+#define PACKAGESLASH "java_director_exception_feature_nspacePackage/"
+%}
+
+%{
+#if defined(_MSC_VER)
+ #pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
+#endif
+
+#include <string>
+%}
+
+%include <std_string.i>
+
+// DEFINE exceptions in header section using std::runtime_error
+%{
+ #include <exception>
+ #include <iostream>
+
+ namespace MyNS {
+
+ struct Exception1 : public std::runtime_error {
+ Exception1(const std::string& what):runtime_error(what) {}
+ };
+ struct Exception2 : public std::runtime_error {
+ Exception2(const std::string& what):runtime_error(what) {}
+ };
+ struct Unexpected : public std::runtime_error {
+ Unexpected(const std::string& what):runtime_error(what) {}
+ };
+
+ }
+
+%}
+
+// Add an explicit handler for Foo::ping, mapping one java exception back to an 'int'
+%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")) {
+ std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
+ throw MyNS::Exception2(msg);
+ } else {
+ std::cerr << "Test failed, unexpected exception thrown: " <<
+ Swig::JavaExceptionMessage(jenv,$error).message() << std::endl;
+ throw std::runtime_error("unexpected exception in Foo::ping");
+ }
+ }
+}
+
+// Use default handler on Foo::pong, with directorthrows typemaps
+
+// directorthrows typemaps for java->c++ conversions
+%typemap(directorthrows) MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected %{
+ if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname")) {
+ std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
+ throw $1_type(msg);
+ }
+%}
+
+// Override the director:except feature so exception specification is not violated
+// (Cannot use built-in default of throw DirectorException)
+%feature("director:except") MyNS::Foo::pong %{
+ jthrowable $error = jenv->ExceptionOccurred();
+ if ($error) {
+ jenv->ExceptionClear();
+ $directorthrowshandlers
+ throw ::MyNS::Unexpected(Swig::JavaExceptionMessage(jenv,$error).message());
+ }
+%}
+
+// TODO 'throws' typemap emitted by emit_action (emit.cxx) has no way
+// to get access to language specific special variables like
+// $javaclassname or $packagepath ("java_director_exception_feature" here)
+
+// throws typemaps for c++->java exception conversions
+%typemap(throws,throws=PACKAGEDOT"MyNS.MyJavaException1") MyNS::Exception1 %{
+ jclass excpcls = jenv->FindClass(PACKAGESLASH"MyNS/MyJavaException1");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+%typemap(throws,throws=PACKAGEDOT"MyNS.MyJavaException1") int %{
+ jclass excpcls = jenv->FindClass(PACKAGESLASH"MyNS/MyJavaException1");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, "Threw some integer");
+ }
+ return $null;
+%}
+
+%typemap(throws,throws=PACKAGEDOT"MyNS.MyJavaException2") MyNS::Exception2 %{
+ jclass excpcls = jenv->FindClass(PACKAGESLASH"MyNS/MyJavaException2");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+
+%typemap(throws,throws=PACKAGEDOT"MyNS.MyJavaUnexpected") MyNS::Unexpected %{
+ jclass excpcls = jenv->FindClass(PACKAGESLASH"MyNS/MyJavaUnexpected");
+ if (excpcls) {
+ jenv->ThrowNew(excpcls, $1.what());
+ }
+ return $null;
+%}
+
+// Use generic exception translation approach like python, ruby
+
+%feature("director:except") MyNS::Foo::genericpong {
+ jthrowable $error = jenv->ExceptionOccurred();
+ if ($error) {
+ jenv->ExceptionClear();
+ throw Swig::DirectorException(jenv,$error);
+ }
+}
+
+// %exception with throws attribute. Need throws attribute for checked exceptions
+%feature ("except",throws="Exception") MyNS::Foo::genericpong %{
+%}
+
+%feature ("except",throws="Exception") MyNS::Bar::genericpong %{
+ try { $action }
+ catch (Swig::DirectorException & direxcp) {
+ direxcp.raiseJavaException(jenv); // jenv always available in JNI code
+ return $null;
+ }
+%}
+
+
+
+%feature("director") Foo;
+
+// Rename exceptions on java side to make translation of exceptions more clear
+%rename(MyJavaException1) MyNS::Exception1;
+%rename(MyJavaException2) MyNS::Exception2;
+%rename(MyJavaUnexpected) MyNS::Unexpected;
+
+%typemap(javabase) ::MyNS::Exception1,::MyNS::Exception2,::MyNS::Unexpected "java.lang.Exception";
+%rename(getMessage) what() const; // Rename all what() methods
+
+namespace MyNS {
+
+ struct Exception1 {
+ Exception1(const std::string& what);
+ const char * what() const;
+ };
+ struct Exception2 {
+ Exception2(const std::string& what);
+ const char * what() const;
+ };
+ struct Unexpected {
+ Unexpected(const std::string& what);
+ const char * what() const;
+ };
+
+}
+// In general it is better to use %catches instead of an exception specification on the method
+// since violating an exception specification calls terminate() preventing catch-all behavior
+// like throwing std::runtime_error. But an exception specification must be used if the
+// actual interface being wrapped does use them.
+%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Foo::pong;
+%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Bar::pong;
+
+%inline %{
+
+namespace MyNS {
+
+class Foo {
+public:
+ virtual ~Foo() {}
+ // ping java implementation throws a java Exception1 or an Exception2 if excp is 1 or 2.
+ // pong java implementation throws Exception1,Exception2,Unexpected,NullPointerException for 1,2,3,4
+ virtual std::string ping(int excp) throw(int,MyNS::Exception2) = 0;
+ virtual std::string pong(int excp) /* throws MyNS::Exception1 MyNS::Exception2 MyNS::Unexpected) */ = 0;
+ virtual std::string genericpong(int excp) /* unspecified throws - exception is always DirectorException in C++, translated back to whatever thrown in java */ = 0;
+};
+
+// Make a bar from a foo, so a call to Java Bar
+// goes Java Bar -> C++ Bar -> C++ Foo -> Java Foo Director
+
+class Bar {
+public:
+ Bar(Foo* d) { delegate=d; }
+ virtual std::string ping(int excp) throw(int,MyNS::Exception2)
+ {
+ return delegate->ping(excp);
+ }
+
+ virtual std::string pong(int excp) /* throws MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected */
+ {
+ return delegate->pong(excp);
+ }
+
+ virtual std::string genericpong(int excp)
+ {
+ return delegate->genericpong(excp);
+ }
+
+private:
+ Foo * delegate;
+};
+
+}
+%}
diff --git a/Lib/guile/guile_scm_run.swg b/Lib/guile/guile_scm_run.swg
index 0ac51f919..2f8f3ae98 100644
--- a/Lib/guile/guile_scm_run.swg
+++ b/Lib/guile/guile_scm_run.swg
@@ -446,13 +446,8 @@ SWIG_Guile_Init ()
SWIGINTERN swig_module_info *
SWIG_Guile_GetModule(void *SWIGUNUSEDPARM(clientdata))
{
- SCM module;
- SCM variable;
-
- module = SWIG_Guile_Init();
-
- variable = scm_module_variable(module,
- scm_from_locale_symbol("swig-type-list-address" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME));
+ SCM module = SWIG_Guile_Init();
+ SCM variable = scm_module_variable(module, scm_from_locale_symbol("swig-type-list-address" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME));
if (scm_is_false(variable)) {
return NULL;
} else {
@@ -463,11 +458,7 @@ SWIG_Guile_GetModule(void *SWIGUNUSEDPARM(clientdata))
SWIGINTERN void
SWIG_Guile_SetModule(swig_module_info *swig_module)
{
- SCM module;
- SCM variable;
-
- module = SWIG_Guile_Init();
-
+ SCM module = SWIG_Guile_Init();
scm_module_define(module,
scm_from_locale_symbol("swig-type-list-address" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME),
scm_from_ulong((unsigned long) swig_module));
diff --git a/Lib/guile/std_vector.i b/Lib/guile/std_vector.i
index 79c716b10..1c55239c1 100644
--- a/Lib/guile/std_vector.i
+++ b/Lib/guile/std_vector.i
@@ -306,7 +306,6 @@ namespace std {
$1 = 1;
} else {
/* check the first element only */
- T* x;
SCM o = scm_vector_ref($input,scm_from_ulong(0));
$1 = CHECK(o) ? 1 : 0;
}
@@ -315,7 +314,6 @@ namespace std {
$1 = 1;
} else if (scm_is_pair($input)) {
/* check the first element only */
- T* x;
SCM head = SCM_CAR($input);
$1 = CHECK(head) ? 1 : 0;
} else {
@@ -335,7 +333,6 @@ namespace std {
$1 = 1;
} else {
/* check the first element only */
- T* x;
SCM o = scm_vector_ref($input,scm_from_ulong(0));
$1 = CHECK(o) ? 1 : 0;
}
@@ -344,7 +341,6 @@ namespace std {
$1 = 1;
} else if (scm_is_pair($input)) {
/* check the first element only */
- T* x;
SCM head = SCM_CAR($input);
$1 = CHECK(head) ? 1 : 0;
} else {
diff --git a/Lib/java/director.swg b/Lib/java/director.swg
index f32fda350..f9ddbeffe 100644
--- a/Lib/java/director.swg
+++ b/Lib/java/director.swg
@@ -7,11 +7,14 @@
#ifdef __cplusplus
-#if defined(DEBUG_DIRECTOR_OWNED)
+#if defined(DEBUG_DIRECTOR_OWNED) || defined(DEBUG_DIRECTOR_EXCEPTION)
#include <iostream>
#endif
+#include <exception>
+
namespace Swig {
+
/* Java object wrapper */
class JObjectWrapper {
public:
@@ -74,8 +77,7 @@ namespace Swig {
}
/* Java proxy releases ownership of C++ object, C++ object is now
- responsible for destruction (creates NewGlobalRef to pin Java
- proxy) */
+ responsible for destruction (creates NewGlobalRef to pin Java proxy) */
void java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) {
if (take_or_release) { /* Java takes ownership of C++ object's lifetime. */
if (!weak_global_) {
@@ -83,7 +85,8 @@ namespace Swig {
jthis_ = jenv->NewWeakGlobalRef(jself);
weak_global_ = true;
}
- } else { /* Java releases ownership of C++ object's lifetime */
+ } else {
+ /* Java releases ownership of C++ object's lifetime */
if (weak_global_) {
jenv->DeleteWeakGlobalRef((jweak)jthis_);
jthis_ = jenv->NewGlobalRef(jself);
@@ -191,8 +194,194 @@ namespace Swig {
swig_self_.java_change_ownership(jenv, jself, take_or_release);
}
};
-}
-#endif /* __cplusplus */
+ // Utility classes and functions for exception handling.
+
+ // Simple holder for a Java string during exception handling, providing access to a c-style string
+ class JavaString {
+ public:
+ JavaString(JNIEnv *jenv, jstring jstr) : jenv_(jenv), jstr_(jstr), cstr_(0) {
+ if (jenv_ && jstr_)
+ cstr_ = (const char *) jenv_->GetStringUTFChars(jstr_, NULL);
+ }
+
+ ~JavaString() {
+ if (jenv_ && jstr_ && cstr_)
+ jenv_->ReleaseStringUTFChars(jstr_, cstr_);
+ }
+
+ const char *c_str(const char *null_string = "null JavaString") const {
+ return cstr_ ? cstr_ : null_string;
+ }
+
+ private:
+ // non-copyable
+ JavaString(const JavaString &);
+ JavaString &operator=(const JavaString &);
+
+ JNIEnv *jenv_;
+ jstring jstr_;
+ const char *cstr_;
+ };
+
+ // Helper class to extract the exception message from a Java throwable
+ class JavaExceptionMessage {
+ public:
+ 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");
+ }
+
+ private:
+ // non-copyable
+ JavaExceptionMessage(const JavaExceptionMessage &);
+ JavaExceptionMessage &operator=(const JavaExceptionMessage &);
+
+ // Get exception message by calling Java method Throwable.getMessage()
+ static jstring exceptionMessageFromThrowable(JNIEnv *jenv, jthrowable throwable) {
+ jstring jmsg = NULL;
+ if (jenv && throwable) {
+ jenv->ExceptionClear(); // Cannot invoke methods with any pending exceptions
+ jclass throwclz = jenv->GetObjectClass(throwable);
+ if (throwclz) {
+ // All Throwable classes have a getMessage() method, so call it to extract the exception message
+ jmethodID getMessageMethodID = jenv->GetMethodID(throwclz, "getMessage", "()Ljava/lang/String;");
+ if (getMessageMethodID)
+ jmsg = (jstring)jenv->CallObjectMethod(throwable, getMessageMethodID);
+ }
+ if (jmsg == NULL && jenv->ExceptionCheck())
+ jenv->ExceptionClear();
+ }
+ return jmsg;
+ }
+
+ JavaString message_;
+ };
+
+ // C++ Exception class for handling Java exceptions thrown during a director method Java upcall
+ class DirectorException : public std::exception {
+ public:
+
+ // Construct exception from a Java throwable
+ DirectorException(JNIEnv *jenv, jthrowable throwable) : classname_(0), msg_(0) {
+
+ // Call Java method Object.getClass().getName() to obtain the throwable's class name (delimited by '/')
+ if (throwable) {
+ jclass throwclz = jenv->GetObjectClass(throwable);
+ if (throwclz) {
+ jclass clzclz = jenv->GetObjectClass(throwclz);
+ if (clzclz) {
+ jmethodID getNameMethodID = jenv->GetMethodID(clzclz, "getName", "()Ljava/lang/String;");
+ if (getNameMethodID) {
+ jstring jstr_classname = (jstring)(jenv->CallObjectMethod(throwclz, getNameMethodID));
+ // Copy strings, since there is no guarantee that jenv will be active when handled
+ if (jstr_classname) {
+ JavaString jsclassname(jenv, jstr_classname);
+ const char *classname = jsclassname.c_str(0);
+ if (classname)
+ classname_ = copypath(classname);
+ }
+ }
+ }
+ }
+ }
+ JavaExceptionMessage exceptionmsg(jenv, throwable);
+ msg_ = copystr(exceptionmsg.message());
+ }
+
+ // More general constructor for handling as a java.lang.RuntimeException
+ DirectorException(const char *msg) : classname_(0), msg_(copystr(msg ? msg : "Unspecified DirectorException message")) {
+ }
+
+ ~DirectorException() throw() {
+ delete[] classname_;
+ delete[] msg_;
+ }
+
+ const char *what() const throw() {
+ return msg_;
+ }
+
+ // 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();
+
+ 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());
+ }
+ }
+ }
+
+ private:
+ static char *copypath(const char *srcmsg) {
+ char *target = copystr(srcmsg);
+ for (char *c=target; *c; ++c) {
+ if ('.' == *c)
+ *c = '/';
+ }
+ return target;
+ }
+
+ static char *copystr(const char *srcmsg) {
+ char *target = 0;
+ if (srcmsg) {
+ int msglen = strlen(srcmsg) + 1;
+ target = new char[msglen];
+ strncpy(target, srcmsg, msglen);
+ }
+ return target;
+ }
+
+ const char *classname_;
+ const char *msg_;
+ };
+
+ // Helper method to determine if a Java throwable matches a particular Java class type
+ bool ExceptionMatches(JNIEnv *jenv, jthrowable throwable, const char *classname) {
+ bool matches = false;
+
+ if (throwable && jenv && classname) {
+ // Exceptions need to be cleared for correct behavior.
+ // The caller of ExceptionMatches should restore pending exceptions if desired -
+ // the caller already has the throwable.
+ jenv->ExceptionClear();
+
+ jclass clz = jenv->FindClass(classname);
+ if (clz) {
+ jclass classclz = jenv->GetObjectClass(clz);
+ jmethodID isInstanceMethodID = jenv->GetMethodID(classclz, "isInstance", "(Ljava/lang/Object;)Z");
+ if (isInstanceMethodID) {
+ matches = jenv->CallBooleanMethod(clz, isInstanceMethodID, throwable) != 0;
+ }
+ }
+
+#if defined(DEBUG_DIRECTOR_EXCEPTION)
+ if (jenv->ExceptionCheck()) {
+ // Typically occurs when an invalid classname argument is passed resulting in a ClassNotFoundException
+ JavaExceptionMessage exc(jenv, jenv->ExceptionOccurred());
+ std::cout << "Error: ExceptionMatches: class '" << classname << "' : " << exc.message() << std::endl;
+ }
+#endif
+ }
+ return matches;
+ }
+
+}
+
+#endif /* __cplusplus */
diff --git a/Lib/java/std_string.i b/Lib/java/std_string.i
index f178e6d43..5ad7d30bc 100644
--- a/Lib/java/std_string.i
+++ b/Lib/java/std_string.i
@@ -38,7 +38,9 @@ class string;
%typemap(directorout) string
%{ if(!$input) {
- SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ if (!jenv->ExceptionCheck()) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ }
return $null;
}
const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg
index 6a6de0963..79df023de 100644
--- a/Lib/python/pyinit.swg
+++ b/Lib/python/pyinit.swg
@@ -4,6 +4,10 @@
%insert(init) "swiginit.swg"
+#if defined(SWIGPYTHON_BUILTIN)
+%fragment("<stddef.h>"); // For offsetof
+#endif
+
%init %{
#ifdef __cplusplus
diff --git a/Lib/r/rrun.swg b/Lib/r/rrun.swg
index f8bc9f497..990443e23 100644
--- a/Lib/r/rrun.swg
+++ b/Lib/r/rrun.swg
@@ -1,5 +1,6 @@
#ifdef __cplusplus
+#include <exception>
extern "C" {
#endif
@@ -369,7 +370,6 @@ SWIG_R_ConvertPacked(SEXP obj, void *ptr, size_t sz, swig_type_info *ty) {
}
#ifdef __cplusplus
-#include <exception>
#define SWIG_exception_noreturn(code, msg) do { throw std::runtime_error(msg); } while(0)
#else
#define SWIG_exception_noreturn(code, msg) do { return result; } while(0)
diff --git a/Lib/ruby/rubycontainer.swg b/Lib/ruby/rubycontainer.swg
index d4eaa5f73..dd6389ce4 100644
--- a/Lib/ruby/rubycontainer.swg
+++ b/Lib/ruby/rubycontainer.swg
@@ -805,7 +805,6 @@ namespace swig
rb_raise( rb_eTypeError, "not a valid index or range" );
}
- VALUE r = Qnil;
static ID id_end = rb_intern("end");
static ID id_start = rb_intern("begin");
static ID id_noend = rb_intern("exclude_end?");
diff --git a/Lib/ruby/rubyprimtypes.swg b/Lib/ruby/rubyprimtypes.swg
index df72e97f4..aa4f7ad37 100644
--- a/Lib/ruby/rubyprimtypes.swg
+++ b/Lib/ruby/rubyprimtypes.swg
@@ -193,7 +193,7 @@ SWIG_AsVal_dec(unsigned long long)(VALUE obj, unsigned long long *val)
}
%fragment(SWIG_AsVal_frag(double),"header",fragment="SWIG_ruby_failed") {
-%ruby_aux_method(double, NUM2DBL, NUM2DBL(obj))
+%ruby_aux_method(double, NUM2DBL, NUM2DBL(obj); (void)type)
SWIGINTERN int
SWIG_AsVal_dec(double)(VALUE obj, double *val)
diff --git a/Lib/ruby/rubyrun.swg b/Lib/ruby/rubyrun.swg
index e851b1801..c3e0b749b 100644
--- a/Lib/ruby/rubyrun.swg
+++ b/Lib/ruby/rubyrun.swg
@@ -151,14 +151,13 @@ SWIG_Ruby_InitRuntime(void)
SWIGRUNTIME void
SWIG_Ruby_define_class(swig_type_info *type)
{
- VALUE klass;
char *klass_name = (char *) malloc(4 + strlen(type->name) + 1);
sprintf(klass_name, "TYPE%s", type->name);
if (NIL_P(_cSWIG_Pointer)) {
_cSWIG_Pointer = rb_define_class_under(_mSWIG, "Pointer", rb_cObject);
rb_undef_method(CLASS_OF(_cSWIG_Pointer), "new");
}
- klass = rb_define_class_under(_mSWIG, klass_name, _cSWIG_Pointer);
+ rb_define_class_under(_mSWIG, klass_name, _cSWIG_Pointer);
free((void *) klass_name);
}
diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h
index 4856d9e44..65ff70dd9 100644
--- a/Source/Include/swigwarn.h
+++ b/Source/Include/swigwarn.h
@@ -176,6 +176,7 @@
#define WARN_TYPEMAP_OUT_OPTIMAL_IGNORED 474
#define WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE 475
#define WARN_TYPEMAP_INITIALIZER_LIST 476
+#define WARN_TYPEMAP_DIRECTORTHROWS_UNDEF 477
/* -- Fragments -- */
#define WARN_FRAGMENT_NOT_FOUND 490
diff --git a/Source/Modules/guile.cxx b/Source/Modules/guile.cxx
index e0a084583..3a82d67d8 100644
--- a/Source/Modules/guile.cxx
+++ b/Source/Modules/guile.cxx
@@ -24,7 +24,7 @@ Guile Options (available with -guile)\n\
-exportprimitive - Add the (export ...) code from scmstub into the\n\
GOOPS file.\n\
-goopsprefix <prefix> - Prepend <prefix> to all goops identifiers\n\
- -linkage <lstyle> - Use linkage protocol <lstyle> (default `simple')\n\
+ -Linkage <lstyle> - Use linkage protocol <lstyle> (default `simple')\n\
Use `module' for native Guile module linking\n\
(requires Guile >= 1.5.0). Use `passive' for\n\
passive linking (no C-level module-handling code),\n\
@@ -1350,7 +1350,7 @@ public:
Printv(f_header, tm, "\n", NIL);
} else {
// Create variable and assign it a value
- Printf(f_header, "static %s = %s;\n", SwigType_lstr(nctype, var_name), rvalue);
+ Printf(f_header, "static %s = %s;\n", SwigType_str(type, var_name), rvalue);
}
{
/* Hack alert: will cleanup later -- Dave */
diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx
index 24435ac30..6576ad544 100644
--- a/Source/Modules/java.cxx
+++ b/Source/Modules/java.cxx
@@ -192,28 +192,31 @@ public:
*
* Test to see if a type corresponds to something wrapped with a proxy class.
* Return NULL if not otherwise the proxy class name, fully qualified with
- * package name if the nspace feature is used.
+ * package name if the nspace feature is used, unless jnidescriptor is true as
+ * the package name is handled differently (unfortunately for legacy reasons).
* ----------------------------------------------------------------------------- */
- String *getProxyName(SwigType *t) {
+ String *getProxyName(SwigType *t, bool jnidescriptor = false) {
String *proxyname = NULL;
if (proxy_flag) {
Node *n = classLookup(t);
if (n) {
proxyname = Getattr(n, "proxyname");
- if (!proxyname) {
+ if (!proxyname || jnidescriptor) {
String *nspace = Getattr(n, "sym:nspace");
String *symname = Getattr(n, "sym:name");
if (nspace) {
- if (package)
+ if (package && !jnidescriptor)
proxyname = NewStringf("%s.%s.%s", package, nspace, symname);
else
proxyname = NewStringf("%s.%s", nspace, symname);
} else {
proxyname = Copy(symname);
}
- Setattr(n, "proxyname", proxyname);
- Delete(proxyname);
+ if (!jnidescriptor) {
+ Setattr(n, "proxyname", proxyname); // Cache it
+ Delete(proxyname);
+ }
}
}
}
@@ -2885,6 +2888,7 @@ public:
* getEnumName()
*
* If jnidescriptor is set, inner class names are separated with '$' otherwise a '.'
+ * and the package is also not added to the name.
* ----------------------------------------------------------------------------- */
String *getEnumName(SwigType *t, bool jnidescriptor) {
@@ -2899,7 +2903,7 @@ public:
String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name"));
String *proxyname = 0;
if (scopename_prefix) {
- proxyname = getProxyName(scopename_prefix);
+ proxyname = getProxyName(scopename_prefix, jnidescriptor);
}
if (proxyname) {
const char *class_separator = jnidescriptor ? "$" : ".";
@@ -2908,7 +2912,7 @@ public:
// global enum or enum in a namespace
String *nspace = Getattr(n, "sym:nspace");
if (nspace) {
- if (package)
+ if (package && !jnidescriptor)
enumname = NewStringf("%s.%s.%s", package, nspace, symname);
else
enumname = NewStringf("%s.%s", nspace, symname);
@@ -2916,8 +2920,8 @@ public:
enumname = Copy(symname);
}
}
- if (!jnidescriptor) { // not cached
- Setattr(n, "enumname", enumname);
+ if (!jnidescriptor) {
+ Setattr(n, "enumname", enumname); // Cache it
Delete(enumname);
}
Delete(scopename_prefix);
@@ -2935,10 +2939,11 @@ public:
* that SWIG knows about. Also substitutes enums with enum name.
* Otherwise use the $descriptor name for the Java class name. Note that the $&javaclassname substitution
* is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
+ * Note that the path separator is a '.' unless jnidescriptor is set.
* Inputs:
* pt - parameter type
* tm - typemap contents that might contain the special variable to be replaced
- * jnidescriptor - if set, inner class names are separated with '$' otherwise a '.'
+ * jnidescriptor - if set, inner class names are separated with '$' otherwise a '/' is used for the path separator
* Outputs:
* tm - typemap contents complete with the special variable substitution
* Return:
@@ -2984,25 +2989,31 @@ public:
* ----------------------------------------------------------------------------- */
void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable, bool jnidescriptor) {
+ String *replacementname;
+
if (SwigType_isenum(classnametype)) {
String *enumname = getEnumName(classnametype, jnidescriptor);
if (enumname)
- Replaceall(tm, classnamespecialvariable, enumname);
+ replacementname = Copy(enumname);
else
- Replaceall(tm, classnamespecialvariable, NewStringf("int"));
+ replacementname = NewString("int");
} else {
- String *classname = getProxyName(classnametype);
+ String *classname = getProxyName(classnametype, jnidescriptor); // getProxyName() works for pointers to classes too
if (classname) {
- Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too
- } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved.
- String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
- Replaceall(tm, classnamespecialvariable, descriptor);
+ replacementname = Copy(classname);
+ } else {
+ // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved.
+ replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
// Add to hash table so that the type wrapper classes can be created later
- Setattr(swig_types_hash, descriptor, classnametype);
- Delete(descriptor);
+ Setattr(swig_types_hash, replacementname, classnametype);
}
}
+ if (jnidescriptor)
+ Replaceall(replacementname,".","/");
+ Replaceall(tm, classnamespecialvariable, replacementname);
+
+ Delete(replacementname);
}
/* -----------------------------------------------------------------------------
@@ -3497,10 +3508,36 @@ public:
// Delete(method_attr);
}
+ /* -----------------------------------------------------------------------------
+ * substitutePackagePath()
+ *
+ * Replace $packagepath using the javapackage typemap associated with passed
+ * parm or global package if p is 0. "$packagepath/" is replaced with "" if
+ * no package is set. Note that the path separator is a '/'.
+ * ----------------------------------------------------------------------------- */
+
+ void substitutePackagePath(String *text, Parm *p) {
+ String *pkg_path= 0;
+
+ if (p)
+ pkg_path = Swig_typemap_lookup("javapackage", p, "", 0);
+ if (!pkg_path || Len(pkg_path) == 0)
+ pkg_path = Copy(package_path);
+
+ if (Len(pkg_path) > 0) {
+ Replaceall(pkg_path, ".", "/");
+ Replaceall(text, "$packagepath", pkg_path);
+ } else {
+ Replaceall(text, "$packagepath/", empty_string);
+ Replaceall(text, "$packagepath", empty_string);
+ }
+ Delete(pkg_path);
+ }
+
/* ---------------------------------------------------------------
* Canonicalize the JNI field descriptor
*
- * Replace the $javapackage and $javaclassname family of special
+ * Replace the $packagepath and $javaclassname family of special
* variables with the desired package and Java proxy name as
* required in the JNI field descriptors.
*
@@ -3511,27 +3548,11 @@ public:
* --------------------------------------------------------------- */
String *canonicalizeJNIDescriptor(String *descriptor_in, Parm *p) {
- String *pkg_path = Swig_typemap_lookup("javapackage", p, "", 0);
SwigType *type = Getattr(p, "type");
-
- if (!pkg_path || Len(pkg_path) == 0)
- pkg_path = package_path;
-
String *descriptor_out = Copy(descriptor_in);
substituteClassname(type, descriptor_out, true);
-
- if (Len(pkg_path) > 0 && Strchr(descriptor_out, '.') == NULL) {
- Replaceall(descriptor_out, "$packagepath", pkg_path);
- } else {
- Replaceall(descriptor_out, "$packagepath/", empty_string);
- Replaceall(descriptor_out, "$packagepath", empty_string);
- }
-
- Replaceall(descriptor_out, ".", "/");
-
- if (pkg_path != package_path)
- Delete(pkg_path);
+ substitutePackagePath(descriptor_out, p);
return descriptor_out;
}
@@ -3928,17 +3949,33 @@ public:
// Get any Java exception classes in the throws typemap
ParmList *throw_parm_list = NULL;
+ // May need to add Java throws clause to director methods if %catches defined
+ // Get any Java exception classes in the throws typemap
+ ParmList *catches_list = Getattr(n, "catchlist");
+ if (catches_list) {
+ Swig_typemap_attach_parms("throws", catches_list, 0);
+ Swig_typemap_attach_parms("directorthrows", catches_list, 0);
+ for (p = catches_list; p; p = nextSibling(p)) {
+ addThrows(n, "tmap:throws", p);
+ }
+ }
+
if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) {
int gencomma = 0;
Append(w->def, " throw(");
Append(declaration, " throw(");
- if (throw_parm_list)
+ if (throw_parm_list) {
Swig_typemap_attach_parms("throws", throw_parm_list, 0);
+ Swig_typemap_attach_parms("directorthrows", throw_parm_list, 0);
+ }
for (p = throw_parm_list; p; p = nextSibling(p)) {
if (Getattr(p, "tmap:throws")) {
- addThrows(n, "tmap:throws", p);
+ // %catches replaces the specified exception specification
+ if (!catches_list) {
+ addThrows(n, "tmap:throws", p);
+ }
if (gencomma++) {
Append(w->def, ", ");
@@ -4001,7 +4038,8 @@ public:
Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_methids[%s], %s);\n", methop, imclass_name, methid, jupcall_args);
- Printf(w->code, "if (jenv->ExceptionCheck() == JNI_TRUE) return $null;\n");
+ // Generate code to handle any Java exception thrown by director delegation
+ directorExceptHandler(n, catches_list ? catches_list : throw_parm_list, w);
if (!is_void) {
String *jresult_str = NewString("jresult");
@@ -4042,7 +4080,8 @@ public:
/* Terminate wrapper code */
Printf(w->code, "} else {\n");
- Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object\");\n");
+ Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object in %s::%s \");\n",
+ SwigType_namestr(c_classname), SwigType_namestr(name));
Printf(w->code, "}\n");
Printf(w->code, "if (swigjobj) jenv->DeleteLocalRef(swigjobj);\n");
@@ -4099,6 +4138,61 @@ public:
}
/* ------------------------------------------------------------
+ * directorExceptHandler()
+ *
+ * Emit code to map Java exceptions back to C++ exceptions when
+ * feature("director:except") is applied to a method node.
+ * This is generated after the Java method upcall.
+ * ------------------------------------------------------------ */
+
+ void directorExceptHandler(Node *n, ParmList *throw_parm_list, Wrapper *w) {
+
+ String *directorexcept = Getattr(n, "feature:director:except");
+ if (!directorexcept) {
+ directorexcept = NewString("");
+ Printf(directorexcept, "jthrowable $error = jenv->ExceptionOccurred();\n");
+ Printf(directorexcept, "if ($error) {\n");
+ Printf(directorexcept, " jenv->ExceptionClear();$directorthrowshandlers\n");
+ Printf(directorexcept, " throw Swig::DirectorException(jenv, $error);\n");
+ Printf(directorexcept, "}\n");
+ } else {
+ directorexcept = Copy(directorexcept);
+ }
+
+ // Can explicitly disable director:except by setting to "" or "0"
+ if (Len(directorexcept) > 0 && Cmp(directorexcept, "0") != 0) {
+
+ // Replace $packagepath
+ substitutePackagePath(directorexcept, 0);
+
+ // Replace $directorthrowshandlers with any defined typemap handlers (or nothing)
+ if (Strstr(directorexcept, "$directorthrowshandlers")) {
+ String *directorthrowshandlers_code = NewString("");
+
+ for (Parm *p = throw_parm_list; p; p = nextSibling(p)) {
+ String *tm = Getattr(p, "tmap:directorthrows");
+
+ if (tm) {
+ // replace $packagepath/$javaclassname
+ String *directorthrows = canonicalizeJNIDescriptor(tm, p);
+ Printv(directorthrowshandlers_code, directorthrows, NIL);
+ Delete(directorthrows);
+ } else {
+ String *t = Getattr(p,"type");
+ Swig_warning(WARN_TYPEMAP_DIRECTORTHROWS_UNDEF, Getfile(n), Getline(n), "No directorthrows typemap defined for %s\n", SwigType_str(t, 0));
+ }
+ }
+ Replaceall(directorexcept, "$directorthrowshandlers", directorthrowshandlers_code);
+ Delete(directorthrowshandlers_code);
+ }
+
+ Replaceall(directorexcept, "$error", "swigerror");
+ Printf(w->code, " %s\n", directorexcept);
+ }
+ Delete(directorexcept);
+ }
+
+ /* ------------------------------------------------------------
* directorPrefixArgs()
* ------------------------------------------------------------ */
diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx
index 4ade67250..def917019 100644
--- a/Source/Modules/php.cxx
+++ b/Source/Modules/php.cxx
@@ -443,7 +443,6 @@ public:
Append(s_header, " zval **args[2];\n");
Append(s_header, " swig_object_wrapper *value;\n");
Append(s_header, " int type;\n");
- Append(s_header, " int thisown;\n");
Append(s_header, "\n");
Append(s_header, " SWIG_ResetError();\n");
Append(s_header, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n");
diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c
index 4b72bdaa2..506878799 100644
--- a/Source/Swig/stype.c
+++ b/Source/Swig/stype.c
@@ -131,6 +131,7 @@ SwigType *NewSwigType(int t) {
break;
case T_STRING: {
SwigType *t = NewString("char");
+ SwigType_add_qualifier(t, "const");
SwigType_add_pointer(t);
return t;
break;