Returning a C++ class to Java via JNI

2019-03-11 04:41发布

问题:

I'm currently using both C++ and Java in a project and I'd like to be able to send an object which is contained in C++ to my Java interface in order to modify it via a GUI and then send the modification back in C++.

So far I've been returning either nothing, an int or a boolean to Java via the JNI interface. This time I have to send an object through the interface. I have made similar class definition available both in C++ and in Java. I'd like to know how I'd go about creating the object so that I can use it in Java.

In C++ I have:

JNIEXPORT MyObject JNICALL Java_ca_X_Y_Z_C_1getMyObject(JNIEnv* env, jclass, jint number);

This function would get called by Java in order to get the object from the C++ side (the object is contained in a singleton, easily accessible).

On the Java end, I do a simple call to this method,

MyObject anObject = C_getMyObject(3);

which should return me the newly created object.

Java currently returns me a UnsatisfiedLinkError when I do the actual call. What is wrong?

回答1:

Here's the solution I opted to use:

First, I would create a similar object in Java. Then, from C++ I would instanciate it and pass it all the values.

(C++)
clazz = env->FindClass("java/lang/Integer");
jmethodID method = env->GetMethodID(clazz, "<init>", "(I)V");
return env->NewObject(clazz, method, (jint)anInteger);

But then I realised this wasn't very portable and was a bit too complicated.

Instead, I decided to return a string that Java would parse and use to initialize the object on its side.

(JAVA)
String aString = "valuesoftheobject";
MyObject myObject(aString);

MyObject would have a constructor which takes a string. I believe the solution is simple and effective.



回答2:

Another tool you should look at is SWIG. SWIG is a great tool for generate wrappers in other languages (such as Java, Python or C#) for existing C/C++ objects. It will generate automatic Java wrappers around C/C++ objects, and do all the heavy JNI lifting for you.

I use it extensively in Xuggler. To see an example, if you download the Xuggler source code there is a C++ object here:

csrc/com/xuggle/xuggler/IStreamCoder.h

I define a SWIG interface file here:

csrc/com/xuggle/xuggler/IStreamCoder.i

And when run through Swig it generates a Java object (which is stored here)

generate/java/com/xuggle/xuggler/IStreamCoder.java

We can then access that object from Java easily (well, I add some ref counting stuff, but that's pretty advanced). Hope that helps.

Art



回答3:

If your MyObject class is defined in C++, you're not going to be able access its methods in Java. I'd try to define a Java wrapper class around your C object:

Java:
public C_Object() {
   handle = createHandle();
}

private native long createHandle(); // or whatever pointer/handle type?

public void doStuff() {
   _doStuff(handle);
}

private native void _doStuff(long handle);

If you can extrapolate a C api instead, you might try JNA.

Your UnsatisfiedLinkError may be the extra character in your function name as written above, or perhaps it can't handle the MyObject return value?