The library is pretty simple. There is one main class with a few supporting classes. The supporting classes are basically just structs which hold variables.
The first thing to be done is create a Java class similar to the main C++ class. This is called a peer class. The methods in the java class are native functions whose implementations will be done using the Java Native Interface (JNI).
In the java class constructor, a jni call to create the C++ class will need to be made. The java class will also need to override the finalize function in which it will have a jni call to delete the C++ class.
The java class also needs to contain a variable which will be used to contain the pointer to the C++ class.
Now my first problem: How do I implement the JNI function which creates the C++ class? If anyone knows the answer, feel free to leave me a comment.
According to this link, a reinterpret cast is involved.
C++ class:
#include "CPPObject.h"
#include
CppObject::CppObject(int aFoo) {
foo = aFoo;
}
void CppObject::printFoo() {
printf ("Value of foo is: %i\n", foo);
}
Java peer class:
public class CppObjectPeer {
static {
System.loadLibrary("cppobjects");
}
protected long ptr;
public CppObjectPeer(int aFoo) {
this.ptr = createCppObject(aFoo); //create object in native code
}
public void printFoo() {
printFoo(this.ptr); //print from native code
}
//native methods
private final native long createCppObject(int aFoo);
private native void printFoo(long ptr);
}
Jni implementations:
JNIEXPORT jlong JNICALL Java_CppObjectPeer_createCppObject
(JNIEnv *env, jobject obj, jint fooValue) {
CppObject *cppObj = new CppObject(fooValue);
return reinterpret_cast
}
JNIEXPORT void JNICALL Java_CppObjectPeer_printFoo
(JNIEnv *env, jobject obj, jlong ptr) {
CppObject *cppObj = reinterpret_cast
cppObj->printFoo();
}
Well, it looks simple enough. Just not sure why the book: Essential Jni: Java Native Interface (Essential Java), by Rob Gordon doesn't use this technique. Is this a new technique?
The book uses a Registry class and a hash code function to store the pointer to the C++ object. This method seems like a lot of work for what I need. As an alternative, he suggests using get/setCID functions which call get/setLongField functions. The set functions requires an int val be passed in and I don't understand where the val comes from. I guess for now I'm going to try the reinterpret_cast method.
Stay tuned for how it works out.
3 comments:
how did it work?
It worked out great, except in place of the reinterpret_cast call, I cast the return value to a (jlong) in the jni Java_CppObjectPeer_createCppObject function.
When the jlong value is passed into the jni Java_CppObjectPeer_printFoo function,
I cast to the object type instead of using the reinterpret_cast:
CppObject *cppObj = (CppObject*) (ptr);
Hello,
I was looking for some tutorial for communicating between C++ class functions and Java, and I found your blog. Thank you for sharing what you found and how you made it working. It was quite useful.
I tried to work on the code that you posted, but am getting error:
In function Java_CppObjectPeer_printFoo':
CppObjectPeer.cpp:(.text+0x73): undefined reference to `CPPObject::printFoo()'
collect2: ld returned 1 exit status
The following is the implementation of the functions, like you suggested:
#include "CppObjectPeer.h"
#include "CPPObject.h"
#include
JNIEXPORT jlong JNICALL Java_CppObjectPeer_createCppObject (JNIEnv *env, jobject obj, jint fooValue) {
CPPObject *cppObj = new CPPObject(fooValue);
return (jlong)(cppObj);
}
JNIEXPORT void JNICALL Java_CppObjectPeer_printFoo (JNIEnv *env, jobject obj, jlong ptr){
CPPObject *cppObj = (CPPObject*)(ptr);
cppObj->printFoo();
}
Did you get any such error?
Thank you.
Post a Comment