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?
source to share
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));
}
source to share
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.
source to share