JNI: return an object from Java to C ++ and pass it back to Java

I have some Java methods that I need to call from C ++ via JNI. My JNI implementation is based on Can I create Java JNI that calls jdbc?

There are two java files in my Java project. One is to define a class and the other contains the actual methods that C ++ will call.

public class MyObject {
    private static int no;
    private static LocalDateTime time;
    private static String status;
    // getters, setters and toString
}

public class ObjectHandler {
    public static MyObject objectReturnToC;

    public static Object methodA (type1 arg1, type2 arg2, type3 arg3) {
        objectReturnToC = new MyObject();
        // setting fields in returnObject according to passed-in parameters
        return objectReturnToC;
    }
    public static void methodB(Object objectReturnedFromC) {
        // access fields in objectReturnedFromC, do computation and store in
    }
}

      

I created a C ++ DLL in Visual Studio 2010. There JVM.cpp, JVM.h, JavaCalls.h and JavaCalls.cpp

JavaCalls.h

#ifdef JAVACALLSDLL_EXPORTS
#define JAVACALLSDLL_API __declspec(dllexport) 
#else
#define JAVACALLSDLL_API __declspec(dllimport) 
#endif

namespace JavaCalls
{
    class JavaCalls
    {
    public:
        static JAVACALLSDLL_API void *javaMethodA(type1, type2, type3);
        static JAVACALLSDLL_API string toString(void **javaObject);
        static JAVACALLSDLL_API void javaMethodB(void **javaObject);
    };
}

      

JavaCalls.cpp

namespace JavaCalls 
{
    void *JavaCalls::javaMethodA(type1 arg1, type2 arg2, type3 arg3) 
    {
        // invoke JVM
        // Find class, methodID
        jobject javaObject = CallStaticObjectMethod(jMain, "methodA",...);
        return javaObject;
    }
    void JavaCalls::javaMethodB(void** javaObject) {
        // invoke JVM
        // Find class, methodID
        CallStaticVoidMethod(jMain, "methodB",...);
    }
}

      

C ++ calls Java method and methodB using DLL:

int main() 
{
    void* a = JavaCalls::JavaCalls::javaMethodA(arg1, arg2, arg3);
    // doing other stuff and updating fields in a
    JavaCalls::JavaCalls::javaMethodB(static_cast<void**>(a));
}

      

Obviously a passing pointer, wanting to be accessible to C ++, doesn't work. But what should I do to save a Java object in C ++ and pass it back to Java later? Should I create a C ++ struct and display a Java Object field in it using GetObjectField?

+3


source to share


2 answers


I don't quite understand why you need it void**

in your code. If you want to make the interface opaque, just use void*

. Also, be sure to call NewGlobalRef()

and DeleteGlobalRef()

in the return jobject

- this will prevent its destruction by the garbage collector:



void *JavaCalls::javaMethodA(type1 arg1, type2 arg2, type3 arg3) 
{
    jobject javaObject = CallStaticObjectMethod(jMain, "methodA",...);
    return NewGlobalRef(jMain, javaObject);
}

void JavaCalls::javaMethodB(void* javaObject) {
     CallStaticVoidMethod(jMain, "methodB", static_cast<jobject>(javaObject));
}

// add this method - it should be called when you finish using the object
void JavaCalls::ReleaseObject(void* javaObject) {
     DeleteGlobalRef(jMain, static_cast<jobject>(javaObject));
}

      

+3


source


There is a great helper program called javah.exe

.

Write your code however you like and execute javah

in .class

. It will create a fully compatible file for you .h

.

For this you will become:

public class Test {

    public class MyObject {
        private int no;
        private String status;
    }

    public class Callback {
        public void callback(MyObject afterCpp) {

        }
    }

    public native void register(Callback v, MyObject beforeCpp);
}

      



This header:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test */

#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Test
 * Method:    register
 * Signature: (LTest/Callback;LTest/MyObject;)V
 */
JNIEXPORT void JNICALL Java_Test_register
  (JNIEnv *, jobject, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif

      

You just need to call callback

in the third C ++ parameter.

0


source







All Articles