Можно ли вызвать один нативный метод из другого нативного метода? - PullRequest
1 голос
/ 24 сентября 2019

У меня есть класс в Java, который содержит определенные объявления нативных методов.Он содержит вызов метода detroy () в методе finalize, который теперь устарел.В качестве альтернативы финализации я пришел к AutoCloseable с попыткой использования ресурсов.Однако проблема заключается в том, что метод close (), предоставляемый AutoCloseable, который должен быть переопределен в моем классе JSQ, конфликтует с существующим собственным методом close, уже определенным в моем коде.Если я могу найти альтернативное место, из которого можно вызвать разрушение, этого должно быть достаточно в качестве решения.Поэтому я пытаюсь вызвать destroy () из нативного close (), который будет последней точкой, где будет использоваться shdl.Это возможно / разрешено / рекомендовано?У меня нет возможности удалить или изменить встроенный метод 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);?

уничтожить (шдл);?

или любая другая альтернатива, которая может использоваться для удаления finalize () и поиска подходящего места для уничтожения?

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Такое сцепление является законным.В вашем конкретном случае использования это должно быть просто.

Но обычно есть некоторые проблемы, которыми нельзя пренебрегать:

  1. Вызванный метод ожидает корректный указатель env JNI.Поэтому, если вы вызываете его из другого потока, вы обязаны подключить его к JVM.Вы не можете передать JNIEnv * между потоками.

  2. Вызываемый метод ожидает, что все локальные ссылки будут освобождены JVM сразу после его возврата.К счастью, вызывающий может использовать PushLocalFrame() перед вызовом цепочки (и не забывать PopLocalFrame() при возврате.

  3. Вызываемый метод ожидает, что не ожидается никакого исключения JNI. Вызывающий должен проверитьвызывая ExceptionCheck() или ExceptionOccurred(), и если он должен перейти к вызову другого метода, также используйте ExceptionClear(). Было бы разумно, чтобы вызывающий объект проверял исключения после возврата вызываемого.

1 голос
/ 24 сентября 2019

Вызов одного нативного метода из другого фактически разрешен.По крайней мере, я не получил никаких ошибок или предупреждений, когда я сделал это.Но вызов должен включать полное имя функции, как и ожидалось для любого собственного метода - то есть Java_com_project_package_JSQ_destroy, а параметры должны включать:

  1. среда JNI
  2. jobject Object
  3. параметров, ожидаемых по методу.В этом случае shdl

Следовательно, вызов должен быть таким:

Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);

Он должен разместить вызов метода destroy.Тем не менее, он на самом деле не соответствует цели, которую выполняет собственный интерфейс Java, который представляет собой уровень, используемый для того, чтобы код Java мог выполнять вызовы и вызываться родными приложениями и библиотеками, написанными на других языках (здесь, C ++).

...