From 17f65da2149770cf13c7398ce09c2455e4f26537 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Tue, 15 Mar 2005 21:31:31 +0000 Subject: [PATCH] Modifications to the typemaps giving users fine control over memory ownership and lifetime of director classes. Patch from Scott Michel. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7070 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Lib/java/director.swg | 147 ++++++++++++++++++++++-------- Lib/java/java.swg | 70 ++++++++++++--- Source/Modules/java.cxx | 195 +++++++++++++++++++++------------------- 3 files changed, 269 insertions(+), 143 deletions(-) diff --git a/Lib/java/director.swg b/Lib/java/director.swg index a4d8869d4..79cf27d75 100644 --- a/Lib/java/director.swg +++ b/Lib/java/director.swg @@ -12,57 +12,126 @@ #ifdef __cplusplus +#if defined(DEBUG_DIRECTOR_OWNED) +#include +#endif + namespace Swig { + /* Java object wrapper */ + class JObjectWrapper { + public: + JObjectWrapper() : jthis_(NULL), weak_global_(true) { + } + + ~JObjectWrapper() { + jthis_ = NULL; + weak_global_ = true; + } + + bool set(JNIEnv *jenv, jobject jobj, bool mem_own, bool weak_global) { + if (jthis_ == NULL) { + weak_global_ = weak_global; + if (jobj) + jthis_ = ((weak_global_ || !mem_own) ? jenv->NewWeakGlobalRef(jobj) : jenv->NewGlobalRef(jobj)); +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> " << jthis_ << std::endl; +#endif + return true; + } else { +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> already set" << std::endl; +#endif + return false; + } + } + + jobject get(JNIEnv *jenv) const { +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "JObjectWrapper::get("; + if (jthis_) + std::cout << jthis_; + else + std::cout << "null"; + std::cout << ") -> return new local ref" << std::endl; +#endif + return (jthis_ ? jenv->NewLocalRef(jthis_) : jthis_); + } + + void release(JNIEnv *jenv) { +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "JObjectWrapper::release(" << jthis_ << "): " << (weak_global_ ? "local ref" : "global ref") << std::endl; +#endif + if (weak_global_) + jenv->DeleteWeakGlobalRef(jthis_); + else + jenv->DeleteGlobalRef(jthis_); + + jthis_ = NULL; + weak_global_ = true; + } + + jobject peek() { + return jthis_; + } + + private: + /* pointer to Java object */ + jobject jthis_; + /* Local or global reference flag */ + bool weak_global_; + }; + /* director base class */ class Director { - private: - /* pointer to Java virtual machine */ - JavaVM *swig_jvm; + private: + /* pointer to Java virtual machine */ + JavaVM *swig_jvm_; - protected: - /* pointer to the wrapped Java object */ - jobject swig_self; + protected: + /* Java object wrapper */ + JObjectWrapper swig_self_; - /* Acquire Java VM environment from Java VM */ - JNIEnv *swig_acquire_jenv() const { - JNIEnv *env = NULL; - swig_jvm->AttachCurrentThread((void **) &env, NULL); - return env; - } + /* Acquire Java VM environment from Java VM */ + JNIEnv *swig_acquire_jenv() const { + JNIEnv *env = NULL; + swig_jvm_->AttachCurrentThread((void **) &env, NULL); + return env; + } - /* Disconnect director from Java object */ - void swig_disconnect_director_self(const char *disconn_method) { - if (swig_self) { - JNIEnv *jenv = swig_acquire_jenv(); - jmethodID disconn_meth = jenv->GetMethodID(jenv->GetObjectClass(swig_self), disconn_method, "()V"); - if (disconn_meth) { - jenv->CallVoidMethod(swig_self, disconn_meth); - } else { - jenv->ExceptionClear(); - } - jenv->DeleteGlobalRef(swig_self); - swig_self = (jobject) NULL; + /* 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); +#if defined(DEBUG_DIRECTOR_OWNED) + std::cout << "Swig::Director::disconnect_director_self(" << jobj << ")" << std::endl; +#endif + if (jobj) { + jmethodID disconn_meth = jenv->GetMethodID(jenv->GetObjectClass(jobj), disconn_method, "()V"); + if (disconn_meth) { + jenv->CallVoidMethod(jobj, disconn_meth); + } else { + jenv->ExceptionClear(); } } + } - public: - Director(JNIEnv *jenv) : swig_jvm((JavaVM *) NULL), swig_self(NULL) { - /* Acquire the Java VM pointer */ - jenv->GetJavaVM(&swig_jvm); - } + public: + Director(JNIEnv *jenv) : swig_jvm_((JavaVM *) NULL), swig_self_() { + /* Acquire the Java VM pointer */ + jenv->GetJavaVM(&swig_jvm_); + } - virtual ~Director() { - } + virtual ~Director() { + swig_self_.release(swig_acquire_jenv()); + } - /* Set swig_self and get Java global reference on object */ - void swig_set_self(JNIEnv *jenv, jobject jself) { - swig_self = jenv->NewGlobalRef(jself); - } + bool swig_set_self(JNIEnv *jenv, jobject jself, bool mem_own, bool weak_global) { + return swig_self_.set(jenv, jself, mem_own, weak_global); + } - /* return a pointer to the wrapped Java object */ - jobject swig_get_self() const { - return swig_self; - } + jobject swig_get_self(JNIEnv *jenv) const { + return swig_self_.get(jenv); + } }; } diff --git a/Lib/java/java.swg b/Lib/java/java.swg index dfd8c277f..3cb467076 100644 --- a/Lib/java/java.swg +++ b/Lib/java/java.swg @@ -891,34 +891,43 @@ %typemap(javaimports) SWIGTYPE, SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], SWIGTYPE (CLASS::*) "" %typemap(javainterfaces) SWIGTYPE, SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], SWIGTYPE (CLASS::*) "" -// Proxy classes (base classes, ie, not derived classes) -%typemap(javabody) SWIGTYPE %{ +/* javabody typemaps */ + +%define SWIG_JAVABODY_METHODS(PTRCTOR_VISIBILITY, CPTR_VISIBILITY, TYPENAME...) +// Base proxy classes +%typemap(javabody) TYPENAME %{ private long swigCPtr; protected boolean swigCMemOwn; - protected $javaclassname(long cPtr, boolean cMemoryOwn) { + PTRCTOR_VISIBILITY $javaclassname(long cPtr, boolean cMemoryOwn) { swigCMemOwn = cMemoryOwn; swigCPtr = cPtr; } - protected static long getCPtr($javaclassname obj) { + CPTR_VISIBILITY static long getCPtr($javaclassname obj) { return (obj == null) ? 0 : obj.swigCPtr; } %} // Derived proxy classes -%typemap(javabody_derived) SWIGTYPE %{ +%typemap(javabody_derived) TYPENAME %{ private long swigCPtr; - protected $javaclassname(long cPtr, boolean cMemoryOwn) { + PTRCTOR_VISIBILITY $javaclassname(long cPtr, boolean cMemoryOwn) { super($moduleJNI.SWIG$javaclassnameUpcast(cPtr), cMemoryOwn); swigCPtr = cPtr; } - protected static long getCPtr($javaclassname obj) { + CPTR_VISIBILITY static long getCPtr($javaclassname obj) { return (obj == null) ? 0 : obj.swigCPtr; } %} +%enddef + +/* Set the default for SWIGTYPE: pointer constructor is protected, + getCPtr is protected. Season to your own taste! */ + +SWIG_JAVABODY_METHODS(protected, protected, SWIGTYPE) // Typewrapper classes %typemap(javabody) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [], SWIGTYPE (CLASS::*) %{ @@ -943,14 +952,49 @@ } %} -%typemap(javaconstruct) SWIGTYPE { - this($imcall, true); - } +/* + * 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 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_DIRECTOR_OWNED macro sets the ownership of director-based proxy + * classes to false, meaning that the underlying C++ object will be + * reclaimed by C++. + */ -%typemap(javaconstruct_director) SWIGTYPE { - this($imcall, true); - $moduleJNI.$javaclassname_director_connect(this, swigCPtr); +%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); + } +%enddef + +%define SWIG_DIRECTOR_OWNED(TYPENAME...) +SWIG_DIRECTOR_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) %typemap(javadestruct, methodname="delete") SWIGTYPE { if(swigCPtr != 0 && swigCMemOwn) { diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index 6f68f0387..a6af504ae 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -75,7 +75,6 @@ class JAVA : public Language { Hash *dmethods_table; int n_dmethods; int n_directors; - bool emitted_connect; int first_class_dmethod; int curr_class_dmethod; @@ -139,11 +138,10 @@ class JAVA : public Language { dmethods_seq(NULL), dmethods_table(NULL), n_dmethods(0), - n_directors(0), - emitted_connect(false) + n_directors(0) { /* for now, multiple inheritance in directors is disabled, this - should be easy to implement though */ + should be easy to implement though */ director_multiple_inheritance = 0; director_language = 1; } @@ -270,7 +268,7 @@ class JAVA : public Language { allow_directors(); } if (Getattr(optionsnode, "dirprot")) { - allow_dirprot(); + allow_dirprot(); } } @@ -340,7 +338,6 @@ class JAVA : public Language { dmethods_table = NewHash(); n_dmethods = 0; n_directors = 0; - emitted_connect = false; if (!package) package = NewString(""); jnipackage = NewString(""); package_path = NewString(""); @@ -562,7 +559,6 @@ class JAVA : public Language { Delete(dmethods_seq); dmethods_seq = NULL; Delete(dmethods_table); dmethods_table = NULL; n_dmethods = 0; - emitted_connect = false; /* Close all of the files */ Dump(f_header,f_runtime); @@ -1490,6 +1486,7 @@ class JAVA : public Language { String *baseclass = NULL; String *c_baseclassname = NULL; String *typemap_lookup_type = Getattr(n,"classtypeobj"); + bool feature_director = Swig_directorclass(n); /* Deal with inheritance */ List *baselist = Getattr(n,"bases"); @@ -1580,40 +1577,40 @@ class JAVA : public Language { } /* Insert declaration for directordisconnect/directordisconnect_derived typemap, if this class has directors enabled */ - if (Swig_directorclass(n)) { + if (feature_director) { const String *disconn_tm = NULL; Node *disconn_attr = NewHash(); String *disconn_methodname = NULL; if (derived) { - disconn_tm = typemapLookup("directordisconnect_derived", typemap_lookup_type, WARN_NONE, disconn_attr); - disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect_derived:methodname"); + 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"); + disconn_tm = typemapLookup("directordisconnect", typemap_lookup_type, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); } 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); - } + 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); + Swig_error(input_file, line_number, + "No directordisconnect%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); } Delete(disconn_attr); @@ -1749,7 +1746,7 @@ class JAVA : public Language { Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); Printf(dcast_wrap->code, " %s *obj = *((%s **) &jCPtrBase);\n", norm_name, norm_name); Printf(dcast_wrap->code, " if (obj) director = dynamic_cast(obj);\n"); - Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self();\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); Printf(dcast_wrap->code, " return jresult;\n"); Printf(dcast_wrap->code, "}\n"); @@ -1757,14 +1754,13 @@ class JAVA : public Language { DelWrapper(dcast_wrap); } + emitDirectorExtraMethods(n); + Delete(proxy_class_name); proxy_class_name = NULL; Delete(destructor_call); destructor_call = NULL; Delete(proxy_class_constants_code); proxy_class_constants_code = NULL; } - /* Reinitialize per-class director vars */ - emitted_connect = false; - return SWIG_OK; } @@ -2075,45 +2071,6 @@ class JAVA : public Language { Printf(function_code, "\n"); Replaceall(function_code, "$imcall", imcall); - /* Add director connection call if this class has directors. */ - - if (feature_director) { - 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); -// Printv(function_code, " ", imclass_name, ".", swig_director_connect, "(this, swigCPtr);\n", NIL); - - if (!emitted_connect) { - String *swig_director_connect_jni = makeValidJniName(swig_director_connect); - Wrapper *conn_wrap; - - Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr);\n", swig_director_connect, - proxy_class_name); - - conn_wrap = NewWrapper(); - Printf(conn_wrap->def, "JNIEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg) {", - jnipackage, jni_imclass_name, swig_director_connect_jni); - Printf(conn_wrap->code, " %s *obj = *((%s **) &objarg);\n", norm_name, norm_name); - Printf(conn_wrap->code, " (void)jcls;\n"); - Printf(conn_wrap->code, " SwigDirector_%s *director = dynamic_cast(obj);\n", - Getattr(n, "sym:name"), Getattr(n, "sym:name")); - Printf(conn_wrap->code, " if (director) {\n"); - Printf(conn_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself));\n"); - Printf(conn_wrap->code, " }\n"); - Printf(conn_wrap->code, "}\n"); - - Wrapper_print(conn_wrap, f_wrappers); - DelWrapper(conn_wrap); - - Delete(swig_director_connect_jni); - emitted_connect = true; - } - Delete(norm_name); - Delete(jni_imclass_name); - Delete(swig_director_connect); - } - Printv(proxy_class_code, function_code, "\n", NIL); Delete(overloaded_name); @@ -2777,6 +2734,49 @@ class JAVA : public Language { } } + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the $javaclassname_director_connect is + * generated. + *--------------------------------------------------------------------*/ + 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; + + 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); + + 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"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect_jni); + Delete(norm_name); + Delete(jni_imclass_name); + Delete(swig_director_connect); + } + } + /* --------------------------------------------------------------- * Canonicalize the JNI field descriptor * @@ -2859,7 +2859,7 @@ class JAVA : public Language { String *jniret_desc = NewString(""); String *classret_desc = NewString(""); SwigType *jniret_type = NULL; - String *jupcall_args = NewString("swig_get_self()"); + String *jupcall_args = NewString("swig_get_self(jenv)"); String *imclass_dmethod; Wrapper *imw = NewWrapper(); String *imcall_args = NewString(""); @@ -2888,8 +2888,28 @@ class JAVA : public Language { if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { Wrapper_add_localv(w, "result", SwigType_lstr(returntype, "result"), NIL); } else { - /* initialize pointers to something sane. */ - Wrapper_add_localv(w, "result", SwigType_lstr(returntype, "result"), "= 0", NIL); + String *base_typename = SwigType_base(returntype); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(base_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode != NULL && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "result", SwigType_lstr(returntype, "result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), + "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "result", SwigType_lstr(returntype, "result"), "= &result_default", NIL); + + Delete(non_ref_type); + } } } else { SwigType *vt; @@ -3455,7 +3475,7 @@ class JAVA : public Language { Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); Printf(f_directors_h, "\npublic:\n"); - Printf(f_directors_h, " void swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls);\n"); + Printf(f_directors_h, " void swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global);\n"); /* Keep track of the director methods for this class */ first_class_dmethod = curr_class_dmethod = n_dmethods; @@ -3497,9 +3517,9 @@ class JAVA : public Language { } Printv(w->code, - " swig_disconnect_director_self(\"", disconn_methodname, "\");\n", - "}\n", - NIL); + " swig_disconnect_director_self(\"", disconn_methodname, "\");\n", + "}\n", + NIL); Wrapper_print(w, f_directors); @@ -3526,7 +3546,7 @@ class JAVA : public Language { internal_classname = NewStringf("%s", classname); Wrapper_add_localv(w, "baseclass", "static jclass baseclass", " = 0", NIL); - Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls) {", director_classname); + Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname); if (first_class_dmethod != curr_class_dmethod) { Printf(w->def, "static struct {\n"); @@ -3547,7 +3567,7 @@ class JAVA : public Language { Printf(w->def, "};\n"); } - Printf(w->code, "swig_set_self(jenv, jself);\n"); + Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n"); Printf(w->code, "if (baseclass == NULL) {\n"); Printf(w->code, "baseclass = jenv->FindClass(\"%s\");\n", internal_classname); Printf(w->code, "if (baseclass == NULL) return;\n"); @@ -3589,6 +3609,7 @@ class JAVA : public Language { Printf(f_directors_h, "};\n\n"); Printf(w->code, "}\n"); + Printf(w->code, "}\n"); Wrapper_print(w, f_directors); @@ -3637,14 +3658,6 @@ class JAVA : public Language { * ----------------------------------------------------------------------------- */ virtual int abstractClassTest(Node *n) { - /* - This is not needed anymore, since Language::abstractClassTest - implements now a test considering the director case, which can - be abstract. - - if (!Cmp(Getattr(n, "feature:director"), "1")) - return 0; - */ return Language::abstractClassTest(n); } }; /* class JAVA */