aboutsummaryrefslogtreecommitdiff
path: root/Doc/Manual
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2013-11-07 22:48:17 +0000
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2013-11-07 23:14:21 +0000
commitd73f04e925e9210f2c688ef3656e6059eb540565 (patch)
tree506b8c52f243d7cd90c9fcb70865f754be1de060 /Doc/Manual
parent9df7bee57057668ef878e075ae070acfecd515b1 (diff)
downloadswig-d73f04e925e9210f2c688ef3656e6059eb540565.tar.gz
Documentation edit for the director:except feature and directorthrows typemap
Diffstat (limited to 'Doc/Manual')
-rw-r--r--Doc/Manual/Java.html329
-rw-r--r--Doc/Manual/Warnings.html2
2 files changed, 200 insertions, 131 deletions
diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html
index 0e9ba75de..08c80c83a 100644
--- a/Doc/Manual/Java.html
+++ b/Doc/Manual/Java.html
@@ -3556,99 +3556,108 @@ 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>
+<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. In Swig
-2.0, the director class methods ignored java exceptions that occurred
-during method calls dispatched to the Java director class and simply
-returned '$null' to the C++ caller. The default behavior now throws a
-Swig-defined <code>DirectorException</code> C++ exception. A facility
-is now provided to allow translation of thrown Java exceptions into
-C++ exceptions. This can be done in two different ways using
-the <code>%feature("director:except")</code> directive. In the
-simplest approach, a code block is attached to each director method to
-handle the mapping of java exceptions into C++ exceptions.
+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>
-// All the rules to associate a feature with an element apply
%feature("director:except") MyClass::method(int x) {
- jthrowable $error = jenv->ExceptionOccurred();
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
if ($error) {
- jenv->ExceptionClear();
- if (Swig::ExceptionMatches(jenv,$error,"java/lang/IndexOutOfBoundsException"))
- throw std::out_of_range(Swig::JavaExceptionMessage(jenv,$error).message());
- else if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyJavaException"))
- throw MyCppException(Swig::JavaExceptionMessage(jenv,$error).message());
- else
- throw std::runtime_error("Unexpected exception thrown by MyClass::method");
+ 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 {
- void method(int x); /* on C++ side, may get std::runtime_error or MyCppException */
+ /** Throws either a std::out_of_range or MyCppException on error */
+ void method(int x);
}
</pre>
</div>
+
<p>
-This approach allows mapping java exceptions thrown by director methods into
-C++ exceptions, to match the exceptions expected by a C++ caller. There
-need not be any exception specification on the method. This approach gives
-complete flexibility to map exceptions thrown by a java director
-implementation into desired C++ exceptions. The
-function <code>Swig::ExceptionMatches</code>
+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 <code>director:except</code>feature. These simplify
-testing the type of the java exception and constructing C++ exceptions. The
+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, like <code>"java/lang/IOError"</code>. If the throwable class is the same
-type, or derives from the given type, it returns true. Care must be taken to
+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 <a href="#Java_namespaces">nspace
-feature</a>. The variable $error is simply a unique variable name to allow
-assignment of the exception that occurred. The variable $packagepath is
-replaced by the outer package provided for swig generation by the -package
-option. The class <code>Swig::JavaExceptionMessage</code> is a holder
-object giving access to the message from the thrown java exception.
-The message() method returns the exception message as a <code>const char *</code>,
+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>
-If many methods may throw different exceptions, using this approach to
-write handlers for a large number of methods will result in
-duplication of the code in the <code>director:except</code> feature
-code blocks, and will require separate feature definitions for every
-method. So an alternative approach is provided, using typemaps in a
+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
-an <em>exception specification</em> or a <code>%catches</code>
-feature) into Java exceptions, for the generated proxy classes. To
-provide the inverse mapping, the <code>directorthrows</code> typemap
-is provided.
+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>:
-<p>Using directorthrows typemaps allows a
-generic <code>director:except</code> feature to be combined with
-method-specific handling to achieve the desired result. The
-default <code>director:except</code> feature, in combination
-with <code>directorthrows</code> typemaps generate exception mapping
-to C++ exceptions for all the exceptions defined for each method. The
-default definition is shown below.</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 "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->ExceptionOccurred();
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
if ($error) {
- jenv->ExceptionClear();
+ jenv-&gt;ExceptionClear();
$directorthrowshandlers
throw Swig::DirectorException(jenv, $error);
}
@@ -3657,34 +3666,66 @@ default definition is shown below.</p>
</div>
<p>The code generated using the <code>director:except</code> feature
-replaces the <code>$directorthrowshandlers</code> with code that throws
-appropriate C++ exceptions from <code>directorthrows</code> typemaps
-for each exception defined for the method. Just as with
-the <a href="Typemaps.html#throws_typemap">"throws" typemap</a>, the
-possible exceptions may be defined either with an exception
-specification (<code> throw(MyException,std::runtime_error)</code> ) or
-using the <code>%catches</code> feature applied to the method.</p>
+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><em>Note: Using the %catches feature to define the
-handled exceptions is preferred to using exception specifications. If
-the interface is defined with an exception specification the generated
-swig proxy classes will have the same exception specification. In C++
-if exceptions other than those in the specification are thrown, the
-program will be terminated. </em></p>
+<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>
-<p>Because this default definition maps any unhandled java exceptions to
-Swig::DirectorException, any director methods that define exception
-specifications will cause program termination. To simply ignore
-unexpected exceptions, the default can be changed to:
+<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->ExceptionOccurred();
+ jthrowable $error = jenv-&gt;ExceptionOccurred();
if ($error) {
- jenv->ExceptionClear();
+ jenv-&gt;ExceptionClear();
$directorthrowshandlers
- return $null;
+ return $null; // exception is ignored
}
%}
</pre>
@@ -3692,27 +3733,25 @@ unexpected exceptions, the default can be changed to:
</p>
<p>Alternatively an exception compatible with the existing director
-method exception specifications may be thrown. Assuming that all
+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());
+ throw std::runtime_error(Swig::JavaExceptionMessage(jenv, $error).message());
</pre>
</div>
-</p>
<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 <code>directorthrows</code> typemaps. The <code>directorthrows</code> typemap
-provides a code fragment to test for a pending java exception type, and the
-resulting C++ exception that will be thrown. In this example, a
-generic directorthrows typemap is appropriate for all three exceptions - all
-take single string constructors. If the constructors had different constructors,
+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.
@@ -3721,22 +3760,29 @@ it would be neccessary to have separate typemaps for each exception type.
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)
%{
- #include &lt;exception&gt;
namespace MyNS {
- struct NAME : public std::runtime_error { NAME(const std::string& what):runtime_error(what) {}; };
+ struct NAME : public std::runtime_error { NAME(const std::string &amp;what) : runtime_error(what) {} };
}
%}
%enddef
-// Expose c++ exceptions as java Exceptions with getMessage
+
+// 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,fullname=1) MyNS::NAME::what;
+%rename(getMessage) MyNS::NAME::what;
namespace MyNS {
struct NAME {
- NAME(const std::string& what);
+ NAME(const std::string&amp; what);
const char * what();
};
}
@@ -3744,17 +3790,16 @@ namespace MyNS {
DEFINE_EXCEPTION(ExceptionA)
DEFINE_EXCEPTION(ExceptionB)
-DEFINE_EXCEPTION(Unknown)
+DEFINE_EXCEPTION(Unexpected)
-// Mark three methods to map director-thrown exceptions.
-// Standard rules for feature matching apply
+// 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());
+ if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname"))
+ throw $1_type(Swig::JavaExceptionMessage(jenv, $error).message());
%}
DECLARE_EXCEPTION(ExceptionA)
@@ -3769,68 +3814,54 @@ DECLARE_EXCEPTION(Unexpected)
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() {};
+ virtual ~MyClass() {}
};
}
</pre>
</div>
<p>
-In this case the three different <code>directorthrows</code> typemaps will be used
+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. The code block
-in the directorthrows typemap should always throw a c++ exception.
+the exception specification or <code>%catches</code> feature.
</p>
-<p>Note that the <code>directorthrows</code> typemaps are important
+<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 Swig::DirectorException class provides enough information
+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
-$directorthrowshandlers replacement variable from the
+<code>$directorthrowshandlers</code> special variable from the
default <code>director:except</code> feature and simply always
-throwing a Swig::DirectorException will achieve the desired result.
+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, for each method which may get a generic
-DirectorException from a wrapped director method.</p>
+Java exceptions via the <code>Swig::DirectorException::raiseJavaException</code> method,
+as demonstrated with <code>%javaexception</code> below:
+</p>
<div class="code">
<pre>
-%feature ("except",throws="Exception") MyClass::myMeth %{
- try { $action }
- catch (Swig::DirectorException & direxcp) {
- // jenv always available in JNI code
- // raise the java exception that originally caused the DirectorException
- direxcp.raiseJavaException(jenv);
+%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>The <code>throws="Exception"</code> attribute on the exception
-feature is necessary if any of the translated exceptions will be
-checked exceptions, since the java compiler will otherwise assert that
-no checked exceptions can be thrown by the method. This may be more
-specific that the completely generic "Exception" class, of course. A
-similar feature must be added to director methods to allow checked
-exceptions to be thrown from the director method implementations.
-Here, no actual exception handling is needed - the feature simply
-is being used to add a generic checked exception signature to the
-generated director method wrapper. </p>
-
-<div class="code">
-<pre>
-%feature ("except",throws="Exception") MyDirectorClass::myDirMeth %{ %}
-</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>
@@ -5643,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>
@@ -5977,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>
@@ -6072,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 5b507c123..e0debe41c 100644
--- a/Doc/Manual/Warnings.html
+++ b/Doc/Manual/Warnings.html
@@ -499,7 +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. Feature director:except on <em>Class::method</em> with $directorthrowshandlers requires directorthrows typemap for exception <em>Exception</em>
+<li>477. No directorthrows typemap defined for <em>type</em>
</ul>