Search code examples
javajava-native-interfacedeprecatedfunction-callfinalize

Can one native method be called from another native method?


I have a class in Java which contains certain native method declarations. It contains a call to detroy() within finalize method which is now deprecated. As an alternative to finalize, I arrived at AutoCloseable with try-with-resources. However the issue is that, the close() method provided by AutoCloseable which must be overridden in my JSQ class is conflicting with the existing native close method already defined in my code. If I can find an alternate place from which destroy can be called, that should suffice as a solution. Therefore, I'm attempting to call destroy() from the native close() which would be the last point where shdl would be used. Is this possible / allowed / recommended ? I don't have the option of removing or altering native close() which is why I'm attempting to make the call to destroy from native close.

JSQL.java

class JSQ implements AutoCloseable{
    protected long shdl;
    protected JSQ() { log("JSQ constructor"); }
    protected JSQ(String stmt, boolean isd)
        throws DhSQLException
    {
        // calls a set of native methods
        set_shdl();
        setstmt(stmt, shdl);
        setd(isd, shdl);
        prep(shdl);
    }

    // to be removed
    public void finalize()
    {
        destroy(shdl);
    }

    // alternative to finalize
    @Override
    public void close()
    {
        destroy();
    }

    protected void open()
    {
        parOpen (shdl);
    }

    private native void set_shdl() throws DhSQLException;
    private native void setstmt(String s, long shdl) throws DhSQLException;
    private native void setd(boolean b, long shdl);
    private native void prep(long shdl) throws DhSQLException;
    private native void destroy(long shdl);

    protected native void parOpen(long shdl);
    // following method is called from sub-classes of JSQ
    // super.close(shdl);
    protected native void close(long shdl);


    protected void execute() throws DhSQLException
    {
        parExec(shdl);
    }

    protected native void parExec(long shdl);
}

JSQ.cxx

#define SQ ((sq_stsm_t *)(shdl))

JNIEXPORT void JNICALL Java_com_project_package_JSQ_set_shdl
(JNIEnv *env, jobject obj_This)
{
    jclass cls;
    jmethodID mid;
    cls = (env)->GetObjectClass (obj_This);
    mid = (env)->GetMethodID (hThis,"set_JSQ_shdl","(J)V");

    status_t status;
    // memory allocation
    sq_stsm_t * S = new sq_stsm_t(status);
    if(status)
    {
        if (S) { delete S; }
        return;
    }
    // I understand that we're attempting to call a Java method from a native method.
    // But which method is it calling?
    // Also, are we converting S from sq_stms_t type to jlong?
    (env)->CallVoidMethod (obj_This,mid,(jlong) S);
    return;
}

JNIEXPORT void JNICALL Java_com_project_package_JSQ_setstmt
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
    status_t status;

    // cstmt is obtained using jstmt
    status = SQ->SetStmt(cstmt);
    return;
}

JNIEXPORT void JNICALL Java_com_project_package_JSQ_destroy
(JNIEnv *, jobject, jlong shdl)
{
    delete SQ;
}

JNIEXPORT void JNICALL Java_com_project_package_JSQ_close
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
    status_t status;
    status = SQ->CloseSQ();

    // Java_com_project_package_JSQ_destroy(shdl);    ?
    //destroy(shdl);    ?
    return;
}

Java_com_project_package_JSQ_destroy(shdl); ?

destroy(shdl); ?

or any other alternative that can serve the purpose of removing finalize() and finding a suitable place for destroy?


Solution

  • Calling one native method from another is in fact permitted. At least, I did not receive any errors or warnings when I did this. But the call must include the full function name as expected of any native method - i.e. Java_com_project_package_JSQ_destroy and the parameters should include:

    1. the JNI environment
    2. jobject Object
    3. parameters expected by the method. In this case, shdl

    Therefore, the call must be like so:

    Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);
    

    It should place the call to destroy method. However, it doesn't really adhere to the purpose served by the Java Native Interface which is a layer used to allow Java code to make calls to and be called by native applications and libraries written in other languages (here, C++).