1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
%module(directors="1") java_director_exception_feature
%include <std_except.i>
%warnfilter(SWIGWARN_TYPEMAP_DIRECTORTHROWS_UNDEF) MyNS::Foo::directorthrows_warning;
%{
#if defined(_MSC_VER)
#pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
#endif
#include <string>
%}
%include <std_string.i>
// DEFINE exceptions in header section using std::runtime_error
%{
#include <exception>
#include <iostream>
namespace MyNS {
struct Exception1 : public std::runtime_error {
Exception1(const std::string& what):runtime_error(what) {}
};
struct Exception2 : public std::runtime_error {
Exception2(const std::string& what):runtime_error(what) {}
};
struct Unexpected : public std::runtime_error {
Unexpected(const std::string& what):runtime_error(what) {}
};
}
%}
// Add an explicit handler for Foo::ping, mapping one java exception back to an 'int'
%feature("director:except") MyNS::Foo::ping {
jthrowable $error = jenv->ExceptionOccurred();
if ($error) {
jenv->ExceptionClear(); // clear java exception since mapping to c++ exception
if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyJavaException1")) {
throw 1;
} else if (Swig::ExceptionMatches(jenv,$error,"$packagepath/MyJavaException2")) {
std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
throw MyNS::Exception2(msg);
} else {
std::cerr << "Test failed, unexpected exception thrown: " <<
Swig::JavaExceptionMessage(jenv,$error).message() << std::endl;
throw std::runtime_error("unexpected exception in Foo::ping");
}
}
}
// Use default handler on Foo::pong, with directorthrows typemaps
// directorthrows typemaps for java->c++ conversions
%typemap(directorthrows) MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected %{
if (Swig::ExceptionMatches(jenv, $error, "$packagepath/$javaclassname")) {
std::string msg(Swig::JavaExceptionMessage(jenv,$error).message());
throw $1_type(msg);
}
%}
// Override the director:except feature so exception specification is not violated
// (Cannot use built-in default of throw DirectorException)
%feature("director:except") MyNS::Foo::pong %{
jthrowable $error = jenv->ExceptionOccurred();
if ($error) {
jenv->ExceptionClear();
$directorthrowshandlers
throw ::MyNS::Unexpected(Swig::JavaExceptionMessage(jenv,$error).message());
}
%}
// TODO 'throws' typemap emitted by emit_action (emit.cxx) has no way
// to get access to language specific special variables like
// $javaclassname or $packagepath ("java_director_exception_feature" here)
// throws typemaps for c++->java exception conversions
%typemap(throws,throws="MyJavaException1") MyNS::Exception1 %{
(void)$1;
jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException1");
if (excpcls) {
jenv->ThrowNew(excpcls, $1.what());
}
return $null;
%}
%typemap(throws,throws="MyJavaException1") int %{
(void)$1;
jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException1");
if (excpcls) {
jenv->ThrowNew(excpcls, "Threw some integer");
}
return $null;
%}
%typemap(throws,throws="MyJavaException2") MyNS::Exception2 %{
jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaException2");
if (excpcls) {
jenv->ThrowNew(excpcls, $1.what());
}
return $null;
%}
%typemap(throws,throws="MyJavaUnexpected") MyNS::Unexpected %{
jclass excpcls = jenv->FindClass("java_director_exception_feature/MyJavaUnexpected");
if (excpcls) {
jenv->ThrowNew(excpcls, $1.what());
}
return $null;
%}
// Use generic exception translation approach like python, ruby
%feature("director:except") MyNS::Foo::genericpong {
jthrowable $error = jenv->ExceptionOccurred();
if ($error) {
jenv->ExceptionClear();
throw Swig::DirectorException(jenv,$error);
}
}
// %exception with throws attribute. Need throws attribute for checked exceptions
%feature ("except",throws="Exception") MyNS::Foo::genericpong %{
%}
%feature ("except",throws="Exception") MyNS::Bar::genericpong %{
try { $action }
catch (Swig::DirectorException & direxcp) {
direxcp.raiseJavaException(jenv); // jenv always available in JNI code
return $null;
}
%}
%feature("director") Foo;
// Rename exceptions on java side to make translation of exceptions more clear
%rename(MyJavaException1) MyNS::Exception1;
%rename(MyJavaException2) MyNS::Exception2;
%rename(MyJavaUnexpected) MyNS::Unexpected;
%typemap(javabase) ::MyNS::Exception1,::MyNS::Exception2,::MyNS::Unexpected "java.lang.Exception";
%rename(getMessage) what() const; // Rename all what() methods
namespace MyNS {
struct Exception1 {
Exception1(const std::string& what);
const char * what() const;
};
struct Exception2 {
Exception2(const std::string& what);
const char * what() const;
};
struct Unexpected {
Unexpected(const std::string& what);
const char * what() const;
};
}
// In general it is better to use %catches instead of an exception specification on the method
// since violating an exception specification calls terminate() preventing catch-all behavior
// like throwing std::runtime_error. But an exception specification must be used if the
// actual interface being wrapped does use them.
%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Foo::pong;
%catches(MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected) MyNS::Bar::pong;
%inline %{
namespace MyNS {
class Foo {
public:
virtual ~Foo() {}
// ping java implementation throws a java Exception1 or an Exception2 if excp is 1 or 2.
// pong java implementation throws Exception1,Exception2,Unexpected,NullPointerException for 1,2,3,4
virtual std::string ping(int excp) throw(int,MyNS::Exception2) = 0;
virtual std::string pong(int excp) /* throws MyNS::Exception1 MyNS::Exception2 MyNS::Unexpected) */ = 0;
virtual std::string genericpong(int excp) /* unspecified throws - exception is always DirectorException in C++, translated back to whatever thrown in java */ = 0;
virtual std::string directorthrows_warning(int excp) throw(double) { return std::string(); }
};
// Make a bar from a foo, so a call to Java Bar
// goes Java Bar -> C++ Bar -> C++ Foo -> Java Foo Director
class Bar {
public:
Bar(Foo* d) { delegate=d; }
virtual std::string ping(int excp) throw(int,MyNS::Exception2)
{
return delegate->ping(excp);
}
virtual std::string pong(int excp) /* throws MyNS::Exception1,MyNS::Exception2,MyNS::Unexpected */
{
return delegate->pong(excp);
}
virtual std::string genericpong(int excp)
{
return delegate->genericpong(excp);
}
private:
Foo * delegate;
};
}
%}
|