Merge branch 'java-director-exceptions'

* java-director-exceptions:
  Add recent Java director enhancements to the changes file
  Replace DirectorException::raiseJavaException with DirectorException::throwException
  Improve Java director exception customization documentation
  Add Swig::DirectorException directorthrows typemap for Java
  Cosmetic whitespace improvement in generated code from throws typemaps.
  Tidy up director_exception testcase
  Changes to use common DirectorException class
  Improved Java director exceptions documentation
  Java director exception handling improvements
This commit is contained in:
William S Fulton 2017-11-29 20:32:40 +00:00
commit 069ce1f6e9
21 changed files with 709 additions and 224 deletions

15
Lib/go/director.swg Normal file
View file

@ -0,0 +1,15 @@
/* -----------------------------------------------------------------------------
* director.swg
*
* This file contains support for director classes so that Go proxy
* methods can be called from C++.
* ----------------------------------------------------------------------------- */
#include <exception>
namespace Swig {
class DirectorException : public std::exception {
};
}

View file

@ -259,8 +259,10 @@ namespace Swig {
JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable) : message_(jenv, exceptionMessageFromThrowable(jenv, throwable)) {
}
const char *message() const {
return message_.c_str("Could not get exception message in JavaExceptionMessage");
// 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 {
return message_.c_str(null_string);
}
private:
@ -294,10 +296,11 @@ namespace Swig {
public:
// Construct exception from a Java throwable
DirectorException(JNIEnv *jenv, jthrowable throwable) : classname_(0), msg_(0) {
DirectorException(JNIEnv *jenv, jthrowable throwable) : jenv_(jenv), throwable_(throwable), classname_(0), msg_(0) {
// Call Java method Object.getClass().getName() to obtain the throwable's class name (delimited by '/')
if (throwable) {
if (jenv && throwable) {
jenv->ExceptionClear(); // Cannot invoke methods with any pending exceptions
jclass throwclz = jenv->GetObjectClass(throwable);
if (throwclz) {
jclass clzclz = jenv->GetObjectClass(throwclz);
@ -318,11 +321,11 @@ namespace Swig {
}
JavaExceptionMessage exceptionmsg(jenv, throwable);
msg_ = copystr(exceptionmsg.message());
msg_ = copystr(exceptionmsg.message(0));
}
// More general constructor for handling as a java.lang.RuntimeException
DirectorException(const char *msg) : classname_(0), msg_(copystr(msg ? msg : "Unspecified DirectorException message")) {
DirectorException(const char *msg) : jenv_(0), throwable_(0), classname_(0), msg_(msg ? copystr(msg) : 0) {
}
~DirectorException() throw() {
@ -331,31 +334,49 @@ namespace Swig {
}
const char *what() const throw() {
return msg_;
return msg_ ? msg_ : "Unspecified DirectorException message";
}
// 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 {
void throwException(JNIEnv *jenv) const {
if (jenv) {
jenv->ExceptionClear();
if (jenv == jenv_ && throwable_) {
// Throw original exception if not already pending
jthrowable throwable = jenv->ExceptionOccurred();
if (throwable && jenv->IsSameObject(throwable, throwable_) == JNI_FALSE) {
jenv->ExceptionClear();
throwable = 0;
}
if (!throwable)
jenv->Throw(throwable_);
} else {
// Try and reconstruct original exception, but original stacktrace is not reconstructed
jenv->ExceptionClear();
jmethodID ctorMethodID = 0;
jclass throwableclass = 0;
if (classname_) {
throwableclass = jenv->FindClass(classname_);
if (throwableclass)
ctorMethodID = jenv->GetMethodID(throwableclass, "<init>", "(Ljava/lang/String;)V");
}
jmethodID ctorMethodID = 0;
jclass throwableclass = 0;
if (classname_) {
throwableclass = jenv->FindClass(classname_);
if (throwableclass)
ctorMethodID = jenv->GetMethodID(throwableclass, "<init>", "(Ljava/lang/String;)V");
}
if (ctorMethodID) {
jenv->ThrowNew(throwableclass, what());
} else {
SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, what());
}
if (ctorMethodID) {
jenv->ThrowNew(throwableclass, what());
} else {
SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, what());
}
}
}
}
// Deprecated - use throwException
void raiseJavaException(JNIEnv *jenv) const {
throwException(jenv);
}
// Create and throw the DirectorException
static void raise(JNIEnv *jenv, jthrowable throwable) {
throw DirectorException(jenv, throwable);
}
@ -380,11 +401,14 @@ namespace Swig {
return target;
}
JNIEnv *jenv_;
jthrowable throwable_;
const char *classname_;
const char *msg_;
};
// Helper method to determine if a Java throwable matches a particular Java class type
// Note side effect of clearing any pending exceptions
SWIGINTERN bool ExceptionMatches(JNIEnv *jenv, jthrowable throwable, const char *classname) {
bool matches = false;

View file

@ -1051,6 +1051,14 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); }
%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, $1);
return $null; %}
/* For methods to raise/throw the original Java exception thrown in a director method */
%typemap(throws) Swig::DirectorException
%{ $1.throwException(jenv);
return $null; %}
/* Java to C++ DirectorException should already be handled. Suppress warning and do nothing in the
event a user specifies a global: %catches(Swig::DirectorException); */
%typemap(directorthrows) Swig::DirectorException ""
/* Typemaps for code generation in proxy classes and Java type wrapper classes */

View file

@ -46,7 +46,22 @@ namespace Swig {
}
};
struct DirectorTypeMismatchException {
// Base class for director exceptions.
class DirectorException : public std::exception {
public:
static void raise(const char *msg) {
// ... todo
throw(DirectorException());
}
static void raise(const octave_value &ov, const char *msg) {
// ... todo
raise(msg);
}
};
class DirectorTypeMismatchException : public DirectorException {
public:
static void raise(const char *msg) {
// ... todo
throw(DirectorTypeMismatchException());
@ -58,7 +73,8 @@ namespace Swig {
}
};
struct DirectorPureVirtualException {
class DirectorPureVirtualException : public DirectorException {
public:
static void raise(const char *msg) {
// ... todo
throw(DirectorPureVirtualException());

View file

@ -71,6 +71,10 @@
/* raise exception */
%define %raise(obj, type, desc) sv_setsv(get_sv("@", GV_ADD), obj); SWIG_fail %enddef
/* For directors to raise/throw the original exception */
%typemap(throws) Swig::DirectorException
%{ sv_setsv(ERRSV, $1.getNative()); SWIG_fail; %}
/* Include the unified typemap library */
%include <typemaps/swigtypemaps.swg>