From 34712c0108f831b20346eefc5c6e36a5141f7a7d Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Wed, 29 Nov 2017 19:06:34 +0000 Subject: [PATCH] Improve Java director exception customization documentation --- Doc/Manual/Contents.html | 5 +- Doc/Manual/Java.html | 529 +++++++++++++++++++++++++++++---------- Doc/Manual/SWIGPlus.html | 2 +- Doc/Manual/Typemaps.html | 8 +- 4 files changed, 406 insertions(+), 138 deletions(-) diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 061f4e215..5cc796c8d 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -484,7 +484,7 @@
  • "memberin" typemap
  • "varin" typemap
  • "varout" typemap -
  • "throws" typemap +
  • "throws" typemap
  • Some typemap examples
  • Accessing protected members
  • Common customization features diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html index be8392411..2b6ec6ce0 100644 --- a/Doc/Manual/Java.html +++ b/Doc/Manual/Java.html @@ -94,6 +94,9 @@
  • Director threading issues
  • Director performance tuning
  • Java exceptions from directors +
  • Accessing protected members
  • Common customization features @@ -3746,12 +3749,10 @@ Naturally, the SWIG generated C++ code and the generated Java intermediary class
    -public class DirectorDerived extends DirectorBase {
    -  public DirectorDerived() {
    -  }
    -
    +class DirectorDerived extends DirectorBase {
    +  @Override
       public void upcall_method() {
    -    System.out.println("DirectorDerived::upcall_method() invoked.");
    +    System.out.println("DirectorDerived.upcall_method() invoked.");
       }
     }
     
    @@ -3774,7 +3775,7 @@ will result in the following being output:
    -DirectorDerived::upcall_method() invoked.
    +DirectorDerived.upcall_method() invoked.
     
    @@ -3826,15 +3827,89 @@ The disadvantage is that invocation of director methods from C++ when Java doesn With directors routing method calls to Java, and proxies routing them to C++, the handling of exceptions is an important concern. The default behavior for Java exceptions thrown in a director method overridden in Java is -to convert the thrown Java exception into a SWIG defined -DirectorException C++ class exception in the C++ layer and then throw this C++ exception. +to store the thrown Java exception into a SWIG defined +Swig::DirectorException C++ class exception in the C++ layer and then throw this C++ exception. +

    + +

    +Of course, should this exception be thrown, your C++ code must catch it and handle it before returning back to Java. +The default generated code does not attempt to handle the C++ exception, but there is a simple way +to make this all work by catching the C++ exception and extracting the original Java exception by using %catches for Swig::DirectorException. +Consider the example shown earlier with a modification to the upcall_method Java method to throw a Java exception: +

    + +
    +
    +class DirectorDerived extends DirectorBase {
    +  @Override
    +  public void upcall_method() {
    +    System.out.println("DirectorDerived.upcall_method() invoked.");
    +    throw new RuntimeException("There was a problem!");
    +  }
    +}
    +
    +
    + +

    +Now, by default, the JVM will abort when example.callup(director) is called as the C++ +Swig::DirectorException (storing the Java exception) is thrown and not handled by the callup method. +Needless to say this is not very user friendly and so the recommendation is to add the following +simple %catches directive before SWIG parses the callup function: +

    + +
    +
    +%catches(Swig::DirectorException) callup;
    +
    +
    + +

    +Or target all wrapped methods using: +

    + +
    +
    +%catches(Swig::DirectorException);
    +
    +
    + +

    +This tells SWIG to generate a C++ catch handler using some code from the throws typemap for Swig::DirectorException that SWIG supplies by default, see Exception handling with %catches. +This typemap code is written to simply catch the C++ Swig::DirectorException class and immediately +return to Java throwing the original Java exception that it has stored. +The net result is a stack trace containing the original Java exception including the location that the exception was thown from. +

    + +
    +
    +DirectorDerived.upcall_method() invoked.
    +Exception in thread "main" java.lang.RuntimeException: There was a problem!
    +    at DirectorDerived.upcall_method(runme.java:4)
    +    at exampleJNI.SwigDirector_DirectorBase_upcall_method(exampleJNI.java:20)
    +    at exampleJNI.callup(Native Method)
    +    at example.callup(example.java:12)
    +    at runme.main(runme.java:21)
    +
    +
    + +

    +More on the Swig::DirectorException class can be found in the next section which details how to customize the handling of director exceptions. +

    + +

    25.5.7.1 Customizing director exceptions

    + + +

    +This section is for advanced customization of director exceptions. +The recommendation for most users is to use the simple %catches directive described above as it should be sufficient for most users needs.

    The conversion of Java exceptions into C++ exceptions can be customized in two different ways using the director:except feature. -In the simplest approach, a code block is attached to each director method to +In the first approach, a code block is attached to each director method to handle the mapping of Java exceptions into C++ exceptions. +The code block is generated just after the call up from the C++ director method into the overloaded method in Java. Its primary function is to check if a Java exception has been thrown and then handle it in C++. The example below converts a java.lang.IndexOutOfBoundsException into a C++ std::out_of_range exception and converts a user's Java MyJavaException into a C++ MyCppException exception. @@ -3843,31 +3918,41 @@ If the Java exception doesn't match either of these, a fallback std::runtime

    -%feature("director:except") MyClass::method(int x) {
    +%feature("director:except") MyClass::dirmethod(int x) {
       jthrowable $error = jenv->ExceptionOccurred();
       if ($error) {
         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");
    +    throw std::runtime_error("Unexpected exception thrown in MyClass::dirmethod");
       }
     }
     
     class MyClass {
    +public:
       /** Throws either a std::out_of_range or MyCppException on error */
    -  void method(int x);
    -}
    +  virtual void dirmethod(int x);
    +  virtual ~MyClass();
    +};
     

    -A few special variables are expanded from the director:except feature when generated. -The special variable $error is expanded by SWIG into a unique variable name and -should be used for the -assignment of the exception that occurred. The special variable $packagepath is -replaced by the outer package provided for SWIG generation by the -package option. +A few special variables are expanded within the director:except feature.

    +
      +
    • The special variable $error is expanded into a unique variable name (swigerror) + and should be used for the assignment of the jthrowable exception that occurred.
    • +
    • The special variable $packagepath is + replaced by the outer package provided for SWIG generation by the -package option.
    • +
    • The special variable $directorthrowshandlers is not shown above, but is replaced + by applicable "directorthrows" typemap contents (covered later in this section).
    • +
    • The special variable $null is not shown above, but is replaced + by a suitable default constructed object for returning from the director method (or nothing if + the director method has a void return). +
    • +

    Utility functions/classes in director.swg are provided to aid the exception conversion as follows: @@ -3878,6 +3963,7 @@ Utility functions/classes in director.swg are provided to aid the exception conv namespace Swig { // Helper method to determine if a Java throwable matches a particular Java class type + // Note side effect of clearing any pending exceptions bool ExceptionMatches(JNIEnv *jenv, jthrowable throwable, const char *classname); // Helper class to extract the exception message from a Java throwable @@ -3909,7 +3995,9 @@ namespace Swig { void raiseJavaException(JNIEnv *jenv) const; // Create and throw the DirectorException - static void raise(JNIEnv *jenv, jthrowable throwable); + static void raise(JNIEnv *jenv, jthrowable throwable) { + throw DirectorException(jenv, throwable); + } }; } @@ -3917,10 +4005,7 @@ namespace Swig {

    -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++ exception specifications on the C++ method. The -utility function Swig::ExceptionMatches +The utility function Swig::ExceptionMatches and class Swig::JavaExceptionMessage are provided to simplify writing code for wrappers that use the director:except feature. The function Swig::ExceptionMatches matches the type of the @@ -3928,7 +4013,7 @@ function Swig::ExceptionMatches matches the type of the name, such as "java/lang/IOError". If the throwable class is the same type, or derives from the given type, Swig::ExceptionMatches 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 +generated proxy class will have an additional package qualification, depending on the '-package' argument and use of the nspace feature. The utility class Swig::JavaExceptionMessage is a holder @@ -3939,18 +4024,25 @@ needs to copy it, for example into a std::string or a newly constructed C++ exce

    -Using the above simple approach to +Using the first approach above to write handlers for a large number of methods will require -repetitive duplication of the director:except feature code. -To mitigate this, an alternative approach is provided via typemaps in a +repetitive duplication of the director:except feature code +for each director method. +To mitigate this, a second approach is provided via typemaps in a fashion analagous to the "throws" typemap. -The "throws" typemap provides the second approach to map all the C++ +The "throws" typemap provides a way to map all the C++ exceptions listed in a method's defined exceptions (either from a C++ exception specification or a %catches 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. +Only use this typemap if you wish to write custom conversions of Java exceptions into C++ exceptions +and apply them to many different methods. +The default handling which uses the Swig::DirectorException class should otherwise meet your needs. +

    + +

    The example below converts a Java java.lang.IndexOutOfBoundsException exception to the typemap's type, that is a std::out_of_range C++ exception: @@ -3967,7 +4059,7 @@ to the typemap's type, that is a std::out_of_range C++ exception:

    The "directorthrows" typemap is then used in conjunction with the director:except feature if the $directorthrowshandlers special variable -is used in the feature code. Consider the following, which also happens to be the default: +is used in the code block. Consider the following, which also happens to be the default:

    @@ -3983,34 +4075,33 @@ is used in the feature code. Consider the following, which also happens to be th

    -where Swig::DirectorException::raise is the helper method to throw a C++ Swig::DirectorException. -

    - -
    -
    -  static void raise(JNIEnv *jenv, jthrowable throwable) {
    -    throw DirectorException(jenv, throwable);
    -  }
    -
    -
    - -

    The code generated using the director:except feature -replaces the $directorthrowshandlers 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 +where Swig::DirectorException::raise is the helper method to throw a C++ Swig::DirectorException, see above. +The code generated from the director:except feature +has the $directorthrowshandlers special variable replaced with the code in +the relevant "directorthrows" typemaps, for each and every exception defined for the method. +The relevant exceptions can be defined either with a C++ exception specification or %catches as described for the "throws" typemap.

    -Let's try all this together and consider the following director method: +Let's try and put all this together by considering the following director method:

    -  ...
    +struct X {
       virtual void doSomething(int index) throw (std::out_of_range);
       ...
    +};
    +
    +OR
    +
    +%catches(std::out_of_range) X::doSomething;
    +struct X {
    +  virtual void doSomething(int index);
    +  ...
    +};
     
    @@ -4026,7 +4117,6 @@ if (swigerror) { if (Swig::ExceptionMatches(jenv, swigerror, "java/lang/IndexOutOfBoundsException")) { throw std::out_of_range(Swig::JavaExceptionMessage(jenv, swigerror).message()); } - Swig::DirectorException::raise(jenv, swigerror); } @@ -4035,7 +4125,7 @@ if (swigerror) {

    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 +director method throws an exception that is not specified in the exception specifications list 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. @@ -4043,8 +4133,9 @@ this potential fate.

    Because the default code generation maps any unhandled Java exceptions to Swig::DirectorException, any director methods that have exception -specifications may cause program termination. To simply ignore -unexpected exceptions, the default handling can be changed by adding: +specifications may cause program termination as this exception class won't be in the exception specifications list. +You can avoid throwing Swig::DirectorException by changing the default handling for all methods by adding a director:except feature without any method name. +For example, you can just ignore them:

    @@ -4063,7 +4154,7 @@ unexpected exceptions, the default handling can be changed by adding:

    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 return $null; could be changed to: +the return $null line above could be changed to:

    @@ -4073,122 +4164,296 @@ the return $null; could be changed to:

    In more complex situations, a separate director:except feature -may need to be attached to specific methods. +may need to be attached to specific methods by providing a method name to the director:except feature.

    -

    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 necessary to have separate typemaps for each exception type. +

    This is all no doubt quite hard to follow without seeing a full example and some code. +Below is a complete example demonstrating the use +of most of the exception customizations one can use, that is, +"directorthrows" and "throws" typemaps, %exception and %catches. +See the Exception handling with %exception and %javaexception +section for more on converting C++ exceptions to Java exceptions. +The example also has a user defined C++ exception class called MyNS::MyException and this is wrapped as a Java exception. +The director class being wrapped is MyClass and the director method is called MyClass::dirmethod. +A number of std::cout calls have been added to help understand code flow. +You can copy the code below into an interface file and run SWIG on it and examine the generated code. -

     %module(directors="1") example
     
     %{
    -  #include <string>
       #include <stdexcept>
    +  #include <iostream>
     %}
     
    -// 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 &what) : runtime_error(what) {} };
    +// Generic catch handler for all wrapped methods
    +%exception %{
    +  try {
    +    $action
    +  } catch (const std::exception &e) {
    +    std::cout << "Generic std::exception catch handler" << std::endl;
    +    jclass clazz = jenv->FindClass("java/lang/RuntimeException");
    +    jenv->ThrowNew(clazz, e.what()); 
    +    return $null;
       }
     %}
    -%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;
    +// Expose C++ exception as a Java Exception by changing the Java base class and providing a getMessage()
    +%typemap(javabase) MyNS::MyException "java.lang.RuntimeException";
    +%rename(getMessage) MyNS::MyException::whatsup;
    +
    +%inline %{
     namespace MyNS {
    -  struct NAME {
    -    NAME(const std::string& what);
    -    const char * what();
    +  class MyException {
    +    std::string msg;
    +  public:
    +    MyException(const char *msg) : msg(msg) {}
    +    const char * whatsup() const { return msg.c_str(); }
       };
     }
    -%enddef
    +%}
     
    -DEFINE_EXCEPTION(ExceptionA)
    -DEFINE_EXCEPTION(ExceptionB)
    -DEFINE_EXCEPTION(Unexpected)
    -
    -%typemap(directorthrows) MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected %{
    -  if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname")) {
    +%typemap(directorthrows) MyNS::MyException %{
    +  if (Swig::ExceptionMatches(jenv, $error, "$packagepath/MyException")) {
    +    std::cout << "$1_type exception matched (directorthrows typemap)" << std::endl;
         throw $1_type(Swig::JavaExceptionMessage(jenv, $error).message());
       }
     %}
     
    -DECLARE_EXCEPTION(ExceptionA)
    -DECLARE_EXCEPTION(ExceptionB)
    -DECLARE_EXCEPTION(Unexpected)
    +%typemap(throws) MyNS::MyException %{
    +  std::cout << "$1_type caught (throws typemap)" << std::endl;
    +  jclass excep = jenv->FindClass("MyException");
    +  if (excep) {
    +    std::cout << "$1_type class found (throws typemap)" << std::endl;
    +    jenv->ThrowNew(excep, $1.whatsup());
    +  }
    +  return $null;
    +%}
     
    -%catches(MyNS::ExceptionA, MyNS::ExceptionB, MyNS::Unexpected) MyClass::meth2();
    +// These are the exceptions that the director method MyClass::dirmethod will have catch handlers for.
    +// Note that this is also a virtual method / director method and the C++ exceptions listed can be
    +// thrown after converting them from Java exceptions.
    +%catches(MyNS::MyException, Swig::DirectorException) MyClass::dirmethod;
    +
    +// These are the exceptions that call_dirmethod C++ wrapper will have catch handlers for.
    +// Note that this is not a virtual method, hence not a director method.
    +%catches(MyNS::MyException, Swig::DirectorException) call_dirmethod;
     
     %feature("director") MyClass;
     
    -%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() {}
    -  };
    -}
    -
    -
    - -

    -In this case the three different "directorthrows" typemaps will be used -to generate the three different exception handlers for -meth1, meth2 and meth3. The generated -handlers will have "if" blocks for each exception type, where the exception types are listed in either -the exception specification or %catches feature. -

    - -

    Note that the "directorthrows" typemaps are important -only if it is important for the exceptions passed through the C++ -layer need to be mapped to distinct C++ exceptions. If director methods -are being called by C++ code that is itself wrapped in a -SWIG generated Java wrapper and access is always through this wrapper, -the default Swig::DirectorException class provides enough information -to reconstruct the original exception. In this case removing the -$directorthrowshandlers special variable from the -default director:except feature and simply always -throwing a Swig::DirectorException will achieve the desired result. -Along with this a generic exception feature is added to convert any -caught Swig::DirectorExceptions back into the underlying -Java exceptions via the Swig::DirectorException::raiseJavaException method, -as demonstrated with %javaexception below: -

    - -
    -
    -%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;
    +%feature("director:except") MyClass::dirmethod(int x) {
    +  jthrowable $error = jenv->ExceptionOccurred();
    +  if ($error) {
    +    std::cout << "Upcall finished, an exception was thrown in Java" << std::endl;
    +    $directorthrowshandlers
    +    std::cout << "Upcall finished, no exception conversion, throwing DirectorException" << std::endl;
    +    Swig::DirectorException::raise(jenv, $error);
       }
    +}
    +
    +%inline %{
    +class MyClass {
    +public:
    +  /** Throws either a std::out_of_range or MyException on error */
    +  virtual void dirmethod(int x) {
    +    if (x <= 0)
    +      throw std::out_of_range("MyClass::dirmethod index is out of range");
    +    else if (x == 1)
    +      throw MyNS::MyException("MyClass::dirmethod some problem!");
    +  }
    +  virtual ~MyClass() {}
    +  static void call_dirmethod(MyClass& c, int x) {
    +    return c.dirmethod(x);
    +  }
    +};
     %}
     

    -See the Exception handling with %exception and %javaexception -section for more on converting C++ exceptions to Java exceptions. +The generated code for the call_dirmethod wrapper contains the various exception handlers. +The outer exception handler is from the %exception directive and the others +are from the "throws" typemaps.

    +
    +
    +SWIGEXPORT void JNICALL Java_exampleJNI_MyClass_1call_1dirmethod(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2) {
    +  ...
    +  try {
    +    try {
    +      MyClass::call_dirmethod(*arg1,arg2);
    +    } catch(MyNS::MyException &_e) {
    +      std::cout << "MyNS::MyException caught (throws typemap)" << std::endl;
    +      jclass excep = jenv->FindClass("MyException");
    +      if (excep) {
    +        std::cout << "MyNS::MyException class found (throws typemap)" << std::endl;
    +        jenv->ThrowNew(excep, (&_e)->whatsup());
    +      }
    +      return ;
    +      
    +    } catch(Swig::DirectorException &_e) {
    +      (&_e)->raiseJavaException(jenv);
    +      return ; 
    +    }
    +  } catch (const std::exception &e) {
    +    std::cout << "Generic std::exception catch handler" << std::endl;
    +    jclass clazz = jenv->FindClass("java/lang/RuntimeException");
    +    jenv->ThrowNew(clazz, e.what()); 
    +    return ;
    +  }
    +
    +
    + +

    +The director method calling up to Java contains the exception handling code from the "directorthrows" typemaps and director:except feature. +

    + +
    +
    +void SwigDirector_MyClass::dirmethod(int x) {
    +      ... [call up to Java using CallStaticVoidMethod]
    +      jthrowable swigerror = jenv->ExceptionOccurred();
    +      if (swigerror) {
    +        std::cout << "Upcall finished, an exception was thrown in Java" << std::endl;
    +        
    +        if (Swig::ExceptionMatches(jenv, swigerror, "MyException")) {
    +          std::cout << "MyNS::MyException exception matched (directorthrows typemap)" << std::endl;
    +          throw MyNS::MyException(Swig::JavaExceptionMessage(jenv, swigerror).message());
    +        }
    +        
    +        std::cout << "Upcall finished, no exception conversion, throwing DirectorException" << std::endl;
    +        Swig::DirectorException::raise(jenv, swigerror);
    +      }
    +
    +
    + +

    +Let's use the following Java class to override the director method. +

    + +
    +
    +class DerivedClass extends MyClass {
    +  @Override
    +  public void dirmethod(int x) {
    +    if (x < 0)
    +      throw new IndexOutOfBoundsException("Index is negative");
    +    else if (x == 0)
    +      throw new MyException("MyException: bad dirmethod");
    +  }
    +}
    +public class runme {
    +  public static void main(String argv[]) {
    +    System.loadLibrary("example");
    +    ... code snippets shown below ...
    +  }
    +}
    +
    +
    + +

    +Consider the output using the Java code in the four slightly different scenarios below. +

    + +

    +1. Non-director C++ class is used, thus, no upcall to a Java director method is made. +A std::out_of_range exception is thrown, which is derived from std::exception, +and hence caught by the generic exception handler in the call_dirmethod wrapper. +The Java code snippet and resulting output is: +

    + + +
    +
    +MyClass.call_dirmethod(new MyClass(), 0);
    +
    +
    + +
    +
    +Generic std::exception catch handler
    +Exception in thread "main" java.lang.RuntimeException: MyClass::dirmethod index is out of range
    +        at exampleJNI.MyClass_call_dirmethod(Native Method)
    +        at MyClass.call_dirmethod(MyClass.java:57)
    +        at runme.main(runme.java:14)
    +
    +
    + +

    +2. Non-director C++ class again but this time the MyNS::MyException class is thrown and caught: +

    + +
    +
    +MyClass.call_dirmethod(new MyClass(), 1);
    +
    +
    + +
    +
    +MyNS::MyException caught (throws typemap)
    +MyNS::MyException class found (throws typemap)
    +Exception in thread "main" MyException: MyClass::dirmethod some problem!
    +        at exampleJNI.MyClass_call_dirmethod(Native Method)
    +        at MyClass.call_dirmethod(MyClass.java:57)
    +        at runme.main(runme.java:15)
    +
    +
    + +

    +3. The DerivedClass director class is used so the upcall to Java occurs, but it throws +a Java MyException, which gets converted into a C++ MyNS::MyException, then caught and converted back +into a Java MyException: +

    + +
    +
    +MyClass.call_dirmethod(new DerivedClass(), 0);
    +
    +
    + +
    +
    +Upcall finished, an exception was thrown in Java
    +MyNS::MyException exception matched (directorthrows typemap)
    +MyNS::MyException caught (throws typemap)
    +MyNS::MyException class found (throws typemap)
    +Exception in thread "main" MyException: MyException: bad dirmethod
    +        at exampleJNI.MyClass_call_dirmethod(Native Method)
    +        at MyClass.call_dirmethod(MyClass.java:57)
    +        at runme.main(runme.java:16)
    +
    +
    + +

    +4. The director class is used again, but this time the director method throws a Java IndexOutOfBoundsException exception which is converted into a C++ Swig::DirectorException, thrown and caught again. +This time the original Java exception is extracted from the Swig::DirectorException and rethrown. +Note that this approach keeps the stack trace information of the original exception, so it has the exact location of where the IndexOutOfBoundsException exception was thrown. +This is arguably an improvement over the approach above that converts from a Java excepton to C++ exception and then back to a new Java exception, losing the location of the original exception. +

    + +
    +
    +MyClass.call_dirmethod(new DerivedClass(), -1);
    +
    +
    + +
    +
    +Upcall finished, an exception was thrown in Java
    +Upcall finished, no exception conversion, throwing DirectorException
    +Exception in thread "main" java.lang.IndexOutOfBoundsException: Index is negative
    +        at DerivedClass.dirmethod(runme.java:5)
    +        at exampleJNI.SwigDirector_MyClass_dirmethod(exampleJNI.java:23)
    +        at exampleJNI.MyClass_call_dirmethod(Native Method)
    +        at MyClass.call_dirmethod(MyClass.java:57)
    +        at runme.main(runme.java:17)
    +
    +
    +

    25.6 Accessing protected members

    diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index 144a24d0a..5eac55261 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -4630,7 +4630,7 @@ The next section details a way of simulating an exception specification or repla Exceptions are automatically handled for methods with an exception specification. Similar handling can be achieved for methods without exception specifications through the %catches feature. It is also possible to replace any declared exception specification using the %catches feature. -In fact, %catches uses the same "throws" typemaps that SWIG uses for exception specifications in handling exceptions. +In fact, %catches uses the same "throws" typemaps that SWIG uses for exception specifications in handling exceptions. The %catches feature must contain a list of possible types that can be thrown. For each type that is in the list, SWIG will generate a catch handler, in the same way that it would for types declared in the exception specification. Note that the list can also include the catch all specification "...". diff --git a/Doc/Manual/Typemaps.html b/Doc/Manual/Typemaps.html index 371d0debd..d0d8d7951 100644 --- a/Doc/Manual/Typemaps.html +++ b/Doc/Manual/Typemaps.html @@ -67,7 +67,7 @@
  • "memberin" typemap
  • "varin" typemap
  • "varout" typemap -
  • "throws" typemap +
  • "throws" typemap
  • Some typemap examples
      @@ -2884,11 +2884,11 @@ The "varout" typemap is used to convert a C/C++ object to an object in the targe language when reading a C/C++ global variable. This is implementation specific.

      -

      11.5.14 "throws" typemap

      +

      11.5.14 "throws" typemap

      -The "throws" typemap is only used when SWIG parses a C++ method with an exception specification or has the %catches feature attached to the method. +The "throws" typemap is only used when SWIG parses a C++ method with an exception specification or has the %catches feature attached to the method (see Exception handling with %catches). It provides a default mechanism for handling C++ methods that have declared the exceptions they will throw. The purpose of this typemap is to convert a C++ exception into an error or exception in the target language. It is slightly different to the other typemaps as it is based around the exception type rather than the type of a parameter or variable. @@ -2913,7 +2913,7 @@ For example:

      As can be seen from the resulting generated code below, SWIG generates an exception handler -with the catch block comprising the "throws" typemap content. +when wrapping the bar function with the catch block comprising the "throws" typemap content.