diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2013-11-07 22:48:17 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2013-11-07 23:14:21 +0000 |
commit | d73f04e925e9210f2c688ef3656e6059eb540565 (patch) | |
tree | 506b8c52f243d7cd90c9fcb70865f754be1de060 /Doc/Manual | |
parent | 9df7bee57057668ef878e075ae070acfecd515b1 (diff) | |
download | swig-d73f04e925e9210f2c688ef3656e6059eb540565.tar.gz |
Documentation edit for the director:except feature and directorthrows typemap
Diffstat (limited to 'Doc/Manual')
-rw-r--r-- | Doc/Manual/Java.html | 329 | ||||
-rw-r--r-- | Doc/Manual/Warnings.html | 2 |
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->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->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->ExceptionOccurred(); if ($error) { - jenv->ExceptionClear(); + jenv->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->ExceptionOccurred(); +if (swigerror) { + jenv->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->ExceptionOccurred(); if ($error) { - jenv->ExceptionClear(); + jenv->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 $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 <string> + #include <stdexcept> +%} + // Define exceptions in header section using std::runtime_error %define DEFINE_EXCEPTION(NAME) %{ - #include <exception> 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 &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& 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 &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> |