Improved Java director exceptions documentation
This commit is contained in:
parent
7aa28e37ec
commit
077bb0b04f
3 changed files with 86 additions and 23 deletions
|
|
@ -3825,17 +3825,20 @@ The disadvantage is that invocation of director methods from C++ when Java doesn
|
||||||
<p>
|
<p>
|
||||||
With directors routing method calls to Java, and proxies routing them
|
With directors routing method calls to Java, and proxies routing them
|
||||||
to C++, the handling of exceptions is an important concern.
|
to C++, the handling of exceptions is an important concern.
|
||||||
The default behavior from SWIG 3.0
|
The default behavior for Java exceptions thrown in a director method overridden in Java is
|
||||||
onwards is to convert the thrown Java exception into a SWIG defined
|
to convert the thrown Java exception into a SWIG defined
|
||||||
<code>DirectorException</code> C++ exception.
|
<code>DirectorException</code> C++ class exception in the C++ layer and then throw this C++ exception.
|
||||||
SWIG 2.0 and earlier versions didn't provide any mechanism to handle the Java director method exceptions in C++.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Converting Java exceptions into C++ exceptions can be done in two different ways using
|
The conversion of Java exceptions into C++ exceptions can be customized in two different ways using
|
||||||
the <code>director:except</code> <a href="Customization.html#Customization_features">feature</a>.
|
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
|
In the simplest approach, a code block is attached to each director method to
|
||||||
handle the mapping of Java exceptions into C++ exceptions.
|
handle the mapping of Java exceptions into C++ exceptions.
|
||||||
|
The example below converts a
|
||||||
|
<tt>java.lang.IndexOutOfBoundsException</tt> into a C++ <tt>std::out_of_range</tt> exception and converts a
|
||||||
|
user's Java <tt>MyJavaException</tt> into a C++ <tt>MyCppException</tt> exception.
|
||||||
|
If the Java exception doesn't match either of these, a fallback <tt>std::runtime_error</tt> C++ exception is thrown.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
|
|
@ -3858,6 +3861,61 @@ class MyClass {
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A few special variables are expanded from the <tt>director:except</tt> feature when generated.
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Utility functions/classes in director.swg are provided to aid the exception conversion as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
namespace Swig {
|
||||||
|
|
||||||
|
// Helper method to determine if a Java throwable matches a particular Java class type
|
||||||
|
bool ExceptionMatches(JNIEnv *jenv, jthrowable throwable, const char *classname);
|
||||||
|
|
||||||
|
// Helper class to extract the exception message from a Java throwable
|
||||||
|
class JavaExceptionMessage {
|
||||||
|
public:
|
||||||
|
JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable);
|
||||||
|
|
||||||
|
// Return a C string of the exception message in the jthrowable passed in the constructor
|
||||||
|
// If no message is available, null_string is return instead
|
||||||
|
const char *message(const char *null_string =
|
||||||
|
"Could not get exception message in JavaExceptionMessage") const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// More general constructor for handling as a java.lang.RuntimeException
|
||||||
|
DirectorException(const char *msg);
|
||||||
|
|
||||||
|
// Return exception message extracted from the Java throwable
|
||||||
|
const char *what() const throw();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Create and throw the DirectorException
|
||||||
|
static void raise(JNIEnv *jenv, jthrowable throwable);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This approach allows a flexible mapping of Java exceptions thrown by director methods into
|
This approach allows a flexible mapping of Java exceptions thrown by director methods into
|
||||||
C++ exceptions expected by a C++ caller. There
|
C++ exceptions expected by a C++ caller. There
|
||||||
|
|
@ -3872,11 +3930,8 @@ type, or derives from the given type, <code>Swig::ExceptionMatches</code> will r
|
||||||
provide the correct fully qualified name, since for wrapped exceptions the
|
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 additional package qualification, depending on
|
||||||
the '-package' argument and use of the <a href="#Java_namespaces">nspace
|
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
|
feature</a>.
|
||||||
should be used for the
|
The utility class <code>Swig::JavaExceptionMessage</code> is a holder
|
||||||
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.
|
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>,
|
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
|
which is only valid during the lifetime of the holder. Any code using this message
|
||||||
|
|
@ -3884,20 +3939,20 @@ needs to copy it, for example into a std::string or a newly constructed C++ exce
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Using the above approach to
|
Using the above simple approach to
|
||||||
write handlers for a large number of methods will require
|
write handlers for a large number of methods will require
|
||||||
repetitive duplication of the <code>director:except</code> feature code.
|
repetitive duplication of the <code>director:except</code> feature code.
|
||||||
To mitigate this, an alternative approach is provided via typemaps in a
|
To mitigate this, an alternative approach is provided via typemaps in a
|
||||||
fashion analagous to
|
fashion analagous to
|
||||||
the <a href="Typemaps.html#throws_typemap">"throws" typemap.</a> The
|
the <a href="Typemaps.html#throws_typemap">"throws" typemap</a>.
|
||||||
"throws" typemap provides an approach to automatically map all the C++
|
The "throws" typemap provides the second approach to map all the C++
|
||||||
exceptions listed in a method's defined exceptions (either from
|
exceptions listed in a method's defined exceptions (either from
|
||||||
a C++ <em>exception specification</em> or a <code>%catches</code>
|
a C++ <em>exception specification</em> or a <code>%catches</code>
|
||||||
feature) into Java exceptions.
|
feature) into Java exceptions.
|
||||||
The "directorthrows" typemap provides the inverse mapping and should contain
|
The "directorthrows" typemap provides the inverse mapping and should contain
|
||||||
code to convert a suitably matching Java exception into a C++ exception.
|
code to convert a suitably matching Java exception into a C++ exception.
|
||||||
The example below converts a Java <code>java.lang.IndexOutOfBoundsException</code> 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>:
|
to the typemap's type, that is a <code>std::out_of_range</code> C++ exception:
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -3928,7 +3983,7 @@ is used in the feature code. Consider the following, which also happens to be th
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
where <tt>Swig::DirectorException::raise</tt> is a helper method in the DirectorException class to throw a C++ exception (implemented in director.swg):
|
where <tt>Swig::DirectorException::raise</tt> is the helper method to throw a C++ <tt>Swig::DirectorException</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
|
|
@ -3948,7 +4003,7 @@ specification or <code>%catches</code> as described for the
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Consider the following director method:
|
Let's try all this together and consider the following director method:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="code">
|
<div class="code">
|
||||||
|
|
@ -3997,8 +4052,8 @@ unexpected exceptions, the default handling can be changed by adding:
|
||||||
%feature("director:except") %{
|
%feature("director:except") %{
|
||||||
jthrowable $error = jenv->ExceptionOccurred();
|
jthrowable $error = jenv->ExceptionOccurred();
|
||||||
if ($error) {
|
if ($error) {
|
||||||
jenv->ExceptionClear();
|
|
||||||
$directorthrowshandlers
|
$directorthrowshandlers
|
||||||
|
jenv->ExceptionClear();
|
||||||
return $null; // exception is ignored
|
return $null; // exception is ignored
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
|
||||||
|
|
@ -2901,12 +2901,18 @@ For example:
|
||||||
PyErr_SetString(PyExc_RuntimeError, $1);
|
PyErr_SetString(PyExc_RuntimeError, $1);
|
||||||
SWIG_fail;
|
SWIG_fail;
|
||||||
%}
|
%}
|
||||||
void bar() throw (const char *);
|
|
||||||
|
// Either an exception specification on the method
|
||||||
|
void bar() throw (const char *);
|
||||||
|
|
||||||
|
// Or a %catches feature attached to the method
|
||||||
|
%catches(const char *) bar();
|
||||||
|
void bar();
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
As can be seen from the generated code below, SWIG generates an exception handler
|
As can be seen from the resulting generated code below, SWIG generates an exception handler
|
||||||
with the catch block comprising the "throws" typemap content.
|
with the catch block comprising the "throws" typemap content.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -2915,8 +2921,7 @@ with the catch block comprising the "throws" typemap content.
|
||||||
...
|
...
|
||||||
try {
|
try {
|
||||||
bar();
|
bar();
|
||||||
}
|
} catch(char const *_e) {
|
||||||
catch(char const *_e) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, _e);
|
PyErr_SetString(PyExc_RuntimeError, _e);
|
||||||
SWIG_fail;
|
SWIG_fail;
|
||||||
}
|
}
|
||||||
|
|
@ -2925,8 +2930,8 @@ catch(char const *_e) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Note that if your methods do not have an exception specification yet they do throw exceptions, SWIG cannot know how to deal with them.
|
Note that if your methods do not have an exception specification but they do throw exceptions and you are not using <tt>%catches</tt>, SWIG cannot know how to deal with them.
|
||||||
For a neat way to handle these, see the <a href="Customization.html#Customization_exception">Exception handling with %exception</a> section.
|
Please also see the <a href="Customization.html#Customization_exception">Exception handling with %exception</a> section for another way to handle exceptions.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<H2><a name="Typemaps_nn39">11.6 Some typemap examples</a></H2>
|
<H2><a name="Typemaps_nn39">11.6 Some typemap examples</a></H2>
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,8 @@ namespace Swig {
|
||||||
JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable) : message_(jenv, exceptionMessageFromThrowable(jenv, throwable)) {
|
JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable) : message_(jenv, exceptionMessageFromThrowable(jenv, throwable)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return a C string of the exception message in the jthrowable passed in the constructor
|
||||||
|
// If no message is available, null_string is return instead
|
||||||
const char *message(const char *null_string = "Could not get exception message in JavaExceptionMessage") const {
|
const char *message(const char *null_string = "Could not get exception message in JavaExceptionMessage") const {
|
||||||
return message_.c_str(null_string);
|
return message_.c_str(null_string);
|
||||||
}
|
}
|
||||||
|
|
@ -369,6 +371,7 @@ namespace Swig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create and throw the DirectorException
|
||||||
static void raise(JNIEnv *jenv, jthrowable throwable) {
|
static void raise(JNIEnv *jenv, jthrowable throwable) {
|
||||||
throw DirectorException(jenv, throwable);
|
throw DirectorException(jenv, throwable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue