diff --git a/Examples/test-suite/java_director.i b/Examples/test-suite/java_director.i index 7e6a54f49..09d48b631 100644 --- a/Examples/test-suite/java_director.i +++ b/Examples/test-suite/java_director.i @@ -96,12 +96,14 @@ public: public boolean disconnectMethodCalled = false; %} -%typemap(directordisconnect_derived, methodname="disconnect_director") hi::Quux1 { +%typemap(directordisconnect, methodname="disconnect_director") hi::Quux1 %{ + public void $methodname() { swigCMemOwn = false; $jnicall; // add in a flag to check this method is really called disconnectMethodCalled = true; } +%} %inline %{ diff --git a/Lib/java/director.swg b/Lib/java/director.swg index 79cf27d75..f204d0d25 100644 --- a/Lib/java/director.swg +++ b/Lib/java/director.swg @@ -59,12 +59,15 @@ namespace Swig { void release(JNIEnv *jenv) { #if defined(DEBUG_DIRECTOR_OWNED) - std::cout << "JObjectWrapper::release(" << jthis_ << "): " << (weak_global_ ? "local ref" : "global ref") << std::endl; + std::cout << "JObjectWrapper::release(" << jthis_ << "): " << (weak_global_ ? "weak global ref" : "global ref") << std::endl; #endif - if (weak_global_) - jenv->DeleteWeakGlobalRef(jthis_); - else - jenv->DeleteGlobalRef(jthis_); + if (jthis_ != NULL) { + if (weak_global_) { + if (jenv->IsSameObject(jthis_, NULL) == JNI_FALSE) + jenv->DeleteWeakGlobalRef(jthis_); + } else + jenv->DeleteGlobalRef(jthis_); + } jthis_ = NULL; weak_global_ = true; @@ -74,6 +77,25 @@ namespace Swig { return jthis_; } + /* Java proxy releases ownership of C++ object, C++ object is now + responsible for destruction (creates NewGlobalRef to pin Java + proxy) */ + void java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { + if (take_or_release) { /* Java takes ownership of C++ object's lifetime. */ + if (!weak_global_) { + jenv->DeleteGlobalRef(jthis_); + jthis_ = jenv->NewWeakGlobalRef(jself); + weak_global_ = true; + } + } else { /* Java releses ownership of C++ object's lifetime */ + if (weak_global_) { + jenv->DeleteWeakGlobalRef(jthis_); + jthis_ = jenv->NewGlobalRef(jself); + weak_global_ = false; + } + } + } + private: /* pointer to Java object */ jobject jthis_; @@ -101,16 +123,17 @@ namespace Swig { /* Disconnect director from Java object */ void swig_disconnect_director_self(const char *disconn_method) { JNIEnv *jenv = swig_acquire_jenv(); - jobject jobj = swig_self_.get(jenv); + jobject jobj = swig_self_.peek(); #if defined(DEBUG_DIRECTOR_OWNED) std::cout << "Swig::Director::disconnect_director_self(" << jobj << ")" << std::endl; #endif - if (jobj) { + if (jobj && jenv->IsSameObject(jobj, NULL) == JNI_FALSE) { jmethodID disconn_meth = jenv->GetMethodID(jenv->GetObjectClass(jobj), disconn_method, "()V"); if (disconn_meth) { +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "Swig::Director::disconnect_director_self upcall to " << disconn_method << std::endl; +#endif jenv->CallVoidMethod(jobj, disconn_meth); - } else { - jenv->ExceptionClear(); } } } @@ -132,6 +155,11 @@ namespace Swig { jobject swig_get_self(JNIEnv *jenv) const { return swig_self_.get(jenv); } + + // Change C++ object's ownership, relative to Java + void swig_java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { + swig_self_.java_change_ownership(jenv, jself, take_or_release); + } }; } diff --git a/Lib/java/java.swg b/Lib/java/java.swg index 3edef25aa..ccd2961d5 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -583,13 +583,13 @@ } $1 = *argp; %} -%typemap(directorout) SWIGTYPE ($&1_type argp) -%{ argp = *($&1_ltype*)&$input; +%typemap(directorout) SWIGTYPE ($1_ltype argp) +%{ argp = *($&1_ltype)&$input; if (!argp) { SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null $1_type"); return $null; } - $1 = *argp; %} + $1 = argp; %} %typemap(out) SWIGTYPE #ifdef __cplusplus @@ -1105,46 +1105,36 @@ SWIG_JAVABODY_METHODS(protected, protected, SWIGTYPE) /* * Java constructor typemaps: * - * The javaconstruct and javaconstruct_director typemaps are inserted when a - * proxy class's constructor is generated. These typemaps allow control over what - * code is executed in the constructor as well as specifying who owns the - * underlying C/C++ object. Normally, Java has ownership and the underlying - * C/C++ object is deallocated when the Java object is finalized (swigCMemOwn - * is true.) If swigCMemOwn is false, C/C++ is ultimately responsible for - * deallocating the underlying object's memory. + * The javaconstruct typemap is inserted when a proxy class's constructor is generated. + * This typemap allows control over what code is executed in the constructor as + * well as specifying who owns the underlying C/C++ object. Normally, Java has + * ownership and the underlying C/C++ object is deallocated when the Java object + * is finalized (swigCMemOwn is true.) If swigCMemOwn is false, C/C++ is + * ultimately responsible for deallocating the underlying object's memory. * - * The SWIG_PROXY_CONSTRUCTOR and SWIG_DIRECTOR_CONSTRUCTOR macros define the - * javaconstruct and javaconstruct_director typemaps for a proxy class for a - * particular TYPENAME. OWNERSHIP is passed as the value of swigCMemOwn to the - * pointer constructor method. SWIG_DIRECTOR_CONSTRUCTOR takes an additional - * parameter, WEAKREF, that determines which kind of Java object reference - * will be used by the C++ director class (WeakGlobalRef vs. GlobalRef.) + * The SWIG_PROXY_CONSTRUCTOR macro defines the javaconstruct typemap for a proxy + * class for a particular TYPENAME. OWNERSHIP is passed as the value of + * swigCMemOwn to the pointer constructor method. WEAKREF determines which kind + * of Java object reference will be used by the C++ director class (WeakGlobalRef + * vs. GlobalRef.) * * The SWIG_DIRECTOR_OWNED macro sets the ownership of director-based proxy - * classes to false, meaning that the underlying C++ object will be - * reclaimed by C++. + * classes and the weak reference flag to false, meaning that the underlying C++ + * object will be reclaimed by C++. */ -%define SWIG_PROXY_CONSTRUCTOR(OWNERSHIP, TYPENAME...) -%typemap(javaconstruct) TYPENAME { - this($imcall, OWNERSHIP); - } -%enddef - -%define SWIG_DIRECTOR_CONSTRUCTOR(OWNERSHIP, WEAKREF, TYPENAME...) -%typemap(javaconstruct_director) TYPENAME { - this($imcall, OWNERSHIP); - $moduleJNI.$javaclassname_director_connect(this, swigCPtr, OWNERSHIP, WEAKREF); +%define SWIG_PROXY_CONSTRUCTOR(OWNERSHIP, WEAKREF, TYPENAME...) +%typemap(javaconstruct,directorconnect="\n $moduleJNI.$javaclassname_director_connect(this, swigCPtr, swigCMemOwn, WEAKREF);") TYPENAME { + this($imcall, OWNERSHIP);$directorconnect } %enddef %define SWIG_DIRECTOR_OWNED(TYPENAME...) -SWIG_DIRECTOR_CONSTRUCTOR(true, false, TYPENAME) +SWIG_PROXY_CONSTRUCTOR(true, false, TYPENAME) %enddef // Set the default for SWIGTYPE: Java owns the C/C++ object. -SWIG_PROXY_CONSTRUCTOR(true, SWIGTYPE) -SWIG_DIRECTOR_CONSTRUCTOR(true, true, SWIGTYPE) +SWIG_PROXY_CONSTRUCTOR(true, true, SWIGTYPE) %typemap(javadestruct, methodname="delete") SWIGTYPE { if(swigCPtr != 0 && swigCMemOwn) { @@ -1163,15 +1153,26 @@ SWIG_DIRECTOR_CONSTRUCTOR(true, true, SWIGTYPE) super.delete(); } -%typemap(directordisconnect, methodname="swigDirectorDisconnect") SWIGTYPE { +%typemap(directordisconnect, methodname="swigDirectorDisconnect") SWIGTYPE %{ + protected void $methodname() { swigCMemOwn = false; $jnicall; } +%} -%typemap(directordisconnect_derived, methodname="swigDirectorDisconnect") SWIGTYPE { +%typemap(directorowner_release, methodname="swigReleaseOwnership") SWIGTYPE %{ + public void $methodname() { swigCMemOwn = false; $jnicall; } +%} + +%typemap(directorowner_take, methodname="swigTakeOwnership") SWIGTYPE %{ + public void $methodname() { + swigCMemOwn = true; + $jnicall; + } +%} /* Java specific directives */ #define %javaconst(flag) %feature("java:const","flag") diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h index 06594abf0..d9e647e9c 100644 --- a/Source/Include/swigwarn.h +++ b/Source/Include/swigwarn.h @@ -191,6 +191,7 @@ #define WARN_JAVA_COVARIANT_RET 822 #define WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF 823 #define WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC 824 +#define WARN_JAVA_NO_DIRECTORCONNECT_ATTR 825 /* please leave 810-829 free for Java */ diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index b41157172..cd09002bd 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -427,7 +427,7 @@ class JAVA : public Language { Printv(f_im, imclass_class_code, NIL); Printv(f_im, imclass_cppcasts_code, NIL); if (Len(imclass_directors) > 0) { - Printf(f_im, "\n/* Director upcall methods: */\n\n"); + Printf(f_im, "\n /* Director upcall methods: */\n\n"); Printv(f_im, imclass_directors, NIL); } @@ -1576,44 +1576,24 @@ class JAVA : public Language { Printv(proxy_class_def, "\n ", "public void ", destruct_methodname, "() ", destruct, "\n", NIL); } - /* Insert declaration for directordisconnect/directordisconnect_derived typemap, if this class has directors enabled */ + /* Insert directordisconnect typemap, if this class has directors enabled */ + /* Also insert the swigTakeOwnership and swigReleaseOwnership methods */ if (feature_director) { - const String *disconn_tm = NULL; - Node *disconn_attr = NewHash(); - String *disconn_methodname = NULL; + String *destruct_jnicall, *release_jnicall, *take_jnicall; - if (derived) { - disconn_tm = typemapLookup("directordisconnect_derived", typemap_lookup_type, WARN_NONE, disconn_attr); - disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect_derived:methodname"); - } else { - disconn_tm = typemapLookup("directordisconnect", typemap_lookup_type, WARN_NONE, disconn_attr); - disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); - } + destruct_jnicall = NewStringf("%s()", destruct_methodname); + release_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, false)", imclass_name, + proxy_class_name); + take_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, true)", + imclass_name, proxy_class_name); - if (*Char(disconn_tm)) { - if (disconn_methodname != NULL) { - String *disconn_call = Copy(disconn_tm); - String *disconn_destruct = Copy(destruct_methodname); - Append(disconn_destruct, "()"); - Replaceall(disconn_call, "$jnicall", disconn_destruct); - Printv(proxy_class_def, - "\n", - " protected void ", disconn_methodname, "() ", - disconn_call, - "\n", - NIL); - Delete(disconn_call); - Delete(disconn_destruct); - } else { - Swig_error(input_file, line_number, - "No directordisconnect%s method name for %s\n", (derived ? "_derived" : ""), proxy_class_name); - } - } else { - Swig_error(input_file, line_number, - "No directordisconnect%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); - } + emitCodeTypemap(false, typemap_lookup_type, "directordisconnect", "methodname", destruct_jnicall); + emitCodeTypemap(false, typemap_lookup_type, "directorowner_release", "methodname", release_jnicall); + emitCodeTypemap(false, typemap_lookup_type, "directorowner_take", "methodname", take_jnicall); - Delete(disconn_attr); + Delete(destruct_jnicall); + Delete(release_jnicall); + Delete(take_jnicall); } Delete(attributes); @@ -1990,6 +1970,8 @@ class JAVA : public Language { String *overloaded_name = getOverloadedName(n); String *mangled_overname = Swig_name_construct(overloaded_name); String *imcall = NewString(""); + String *javaconstruct_tm; + Hash *javaconstruct_attrs; const String *methodmods = Getattr(n,"feature:java:methodmodifiers"); methodmods = methodmods ? methodmods : (!is_public(n) ? protected_string : public_string); @@ -2063,16 +2045,34 @@ class JAVA : public Language { Printf(function_code, ")"); generateThrowsClause(n, function_code); - if (feature_director) { - Printv(function_code, " ", typemapLookup("javaconstruct_director", Getattr(n,"name"), WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF), NIL); - } else { - Printv(function_code, " ", typemapLookup("javaconstruct", Getattr(n,"name"), WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF), NIL); + + /* Insert the javaconstruct typemap, doing the replacement for $directorconnect, as needed */ + javaconstruct_attrs = NewHash(); + javaconstruct_tm = Copy(typemapLookup("javaconstruct", Getattr(n,"name"), + WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF, javaconstruct_attrs)); + if (javaconstruct_tm != NULL) { + if (!feature_director) { + Replaceall(javaconstruct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(javaconstruct_attrs, "tmap:javaconstruct:directorconnect"); + + if (connect_attr != NULL) { + Replaceall(javaconstruct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_JAVA_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"javaconstruct\" typemap.\n", Getattr(n,"name")); + Replaceall(javaconstruct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", javaconstruct_tm, "\n", NIL); } - Printf(function_code, "\n"); + Replaceall(function_code, "$imcall", imcall); Printv(proxy_class_code, function_code, "\n", NIL); + Delete(javaconstruct_tm); + Delete(javaconstruct_attrs); Delete(overloaded_name); Delete(imcall); } @@ -2742,39 +2742,114 @@ class JAVA : public Language { *--------------------------------------------------------------------*/ void emitDirectorExtraMethods(Node *n) { - if (Swig_directorclass(n)) { - String *jni_imclass_name = makeValidJniName(imclass_name); - String *norm_name = SwigType_namestr(Getattr(n, "name")); - String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); - String *swig_director_connect_jni = makeValidJniName(swig_director_connect); - Wrapper *code_wrap; + if (!Swig_directorclass(n)) + return; - Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n", - swig_director_connect, proxy_class_name); + // Output the director connect method: + String *jni_imclass_name = makeValidJniName(imclass_name); + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); + String *swig_director_connect_jni = makeValidJniName(swig_director_connect); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; - code_wrap = NewWrapper(); - Printf(code_wrap->def, - "JNIEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jswig_mem_own, " - "jboolean jweak_global) {\n", - jnipackage, jni_imclass_name, swig_director_connect_jni); - Printf(code_wrap->code, " %s *obj = *((%s **) &objarg);\n", norm_name, norm_name); - Printf(code_wrap->code, " (void)jcls;\n"); - Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast(obj);\n", - Getattr(n, "sym:name"), Getattr(n, "sym:name")); - Printf(code_wrap->code, " if (director) {\n"); - Printf(code_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " - "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); - Printf(code_wrap->code, " }\n"); - Printf(code_wrap->code, "}\n"); + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n", + swig_director_connect, proxy_class_name); - Wrapper_print(code_wrap, f_wrappers); - DelWrapper(code_wrap); + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "JNIEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jswig_mem_own, " + "jboolean jweak_global) {\n", + jnipackage, jni_imclass_name, swig_director_connect_jni); + Printf(code_wrap->code, " %s *obj = *((%s **) &objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast(obj);\n", + sym_name, sym_name); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " + "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); - Delete(swig_director_connect_jni); - Delete(norm_name); - Delete(jni_imclass_name); - Delete(swig_director_connect); + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect_jni); + Delete(swig_director_connect); + + // Output the swigReleaseOwnership, swigTakeOwnership methods: + String *changeown_method_name = NewStringf("%s_change_ownership", proxy_class_name); + String *changeown_jnimethod_name = makeValidJniName(changeown_method_name); + + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", + changeown_method_name, proxy_class_name); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "JNIEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jtake_or_release) {\n", + jnipackage, jni_imclass_name, changeown_jnimethod_name); + Printf(code_wrap->code, " %s *obj = *((%s **) &objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast(obj);\n", + sym_name, sym_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_java_change_ownership(jenv, jself, jtake_or_release);\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(changeown_method_name); + Delete(changeown_jnimethod_name); + Delete(norm_name); + Delete(jni_imclass_name); + } + + /*---------------------------------------------------------------------- + * emitCodeTypemap() + * + * Output a code typemap that uses $methodname and $jnicall, as used + * in the directordisconnect, director_release and director_take + * typemaps. + *--------------------------------------------------------------------*/ + + void + emitCodeTypemap(bool derived, String *lookup_type, const String *typemap, const String *methodname, const String *jnicall) + { + const String *tm = NULL; + Node *tmattrs = NewHash(); + String *lookup_tmname = NewString(typemap); + String *method_attr_name; + String *method_attr; + + if (derived) { + Append(lookup_tmname, "_derived"); } + + tm = typemapLookup(lookup_tmname, lookup_type, WARN_NONE, tmattrs); + method_attr_name = NewStringf("tmap:%s:%s", lookup_tmname, methodname); + method_attr = Getattr(tmattrs, method_attr_name); + + if (*Char(tm)) { + if (method_attr != NULL) { + String *codebody = Copy(tm); + Replaceall(codebody, "$methodname", method_attr); + Replaceall(codebody, "$jnicall", jnicall); + Append(proxy_class_def, codebody); + Delete(codebody); + } else { + Swig_error(input_file, line_number, + "No %s method name attribute for %s\n", lookup_tmname, proxy_class_name); + } + } else { + Swig_error(input_file, line_number, + "No %s typemap for %s\n", lookup_tmname, proxy_class_name); + } + + Delete(tmattrs); + Delete(lookup_tmname); + Delete(method_attr); } /* --------------------------------------------------------------- @@ -2859,7 +2934,7 @@ class JAVA : public Language { String *jniret_desc = NewString(""); String *classret_desc = NewString(""); SwigType *jniret_type = NULL; - String *jupcall_args = NewString("swig_get_self(jenv)"); + String *jupcall_args = NewString("jobj"); String *imclass_dmethod; Wrapper *imw = NewWrapper(); String *imcall_args = NewString(""); @@ -3020,14 +3095,17 @@ class JAVA : public Language { Swig_typemap_attach_parms("out", l, w); Swig_typemap_attach_parms("jni", l, w); Swig_typemap_attach_parms("jtype", l, w); - Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorin", l, w); Swig_typemap_attach_parms("javadirectorin", l, 0); /* Add Java environment pointer to wrapper */ String *jenvstr = NewString("jenv"); + String *jobjstr = NewString("jobj"); Wrapper_add_localv(w, jenvstr, "JNIEnv *", jenvstr, "= (JNIEnv *) NULL", NIL); + Wrapper_add_localv(w, jobjstr, "jobject ", jobjstr, "= (jobject) NULL", NIL); Delete(jenvstr); + Delete(jobjstr); /* Preamble code */ @@ -3043,6 +3121,7 @@ class JAVA : public Language { Delete(super_call); } } else { + Printf(w->code, "jenv = swig_acquire_jenv();\n"); Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaDirectorPureVirtual,\n"); Printf(w->code, " \"Attempted to invoke pure virtual method %s::%s.\");\n", c_classname, name); @@ -3057,6 +3136,8 @@ class JAVA : public Language { Printf(w->code, "}\n"); Printf(w->code, "jenv = swig_acquire_jenv();\n"); + Printf(w->code, "jobj = swig_get_self(jenv);\n"); + Printf(w->code, "if (jobj != NULL && jenv->IsSameObject(jobj, NULL) == JNI_FALSE) {\n"); /* Start the Java field descriptor for the intermediate class's upcall (insert self object) */ Parm *tp = NewParmFromNode(c_classname, empty_str, n); @@ -3286,13 +3367,10 @@ class JAVA : public Language { String *methid = Getattr(udata, "imclass_methodidx"); String *methop = getUpcallJNIMethod(jniret_desc); - if (!is_void) { - Printf(w->code, "jresult = (%s) jenv->%s(Swig::jclass_%s, Swig::director_methids[%s], %s);\n", - jniret_type, methop, imclass_name, methid, jupcall_args); - } else { - Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_methids[%s], %s);\n", - methop, imclass_name, methid, jupcall_args); - } + if (!is_void) Printf(w->code, "jresult = (%s) ", jniret_type); + + Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_methids[%s], %s);\n", + methop, imclass_name, methid, jupcall_args); Printf(w->code, "if (jenv->ExceptionOccurred()) return $null;\n"); @@ -3324,6 +3402,10 @@ class JAVA : public Language { Delete(class_desc); /* Terminate wrapper code */ + Printf(w->code, "} else {\n"); + Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object\");\n"); + Printf(w->code, "}\n"); + if (!is_void) Printf(w->code, "return %s;", qualified_return); @@ -3509,20 +3591,15 @@ class JAVA : public Language { Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); } - /* Ensure that correct directordisconnect/_derived typemap's method name is called + /* Ensure that correct directordisconnect typemap's method name is called * here: */ const String *disconn_tm = NULL; Node *disconn_attr = NewHash(); String *disconn_methodname = NULL; - if (Getattr(current_class, "bases") != NULL) { - disconn_tm = typemapLookup("directordisconnect_derived", full_classname, WARN_NONE, disconn_attr); - disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect_derived:methodname"); - } else { - disconn_tm = typemapLookup("directordisconnect", full_classname, WARN_NONE, disconn_attr); - disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); - } + disconn_tm = typemapLookup("directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); Printv(w->code, " swig_disconnect_director_self(\"", disconn_methodname, "\");\n",