Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I reference C++ objects in Java Code using JNI?

I haven't seen this anywhere (or maybe I'm jsut simple not seeing it) but is there a way to use JNI to return the c/c++ object and use that object in java?

For example (very simple):

class simpleClass{
...
private:
int intVar;
public:
int getIntVar();
void setIntVar(int someNum);
...
}

In my java code, how would I go about doing something like:

...
simpleClass sc = new simpleClass();
sc.setIntVar(9);
System.out.println(sc.getIntVar());
...

I realize this is a VERY simplistic example but I'm just looking for concept - the class I have in mind that is in c++ is very large and am looking to avoid creating a TON of wrapper methods...

If it's not possible that's fine, just hoping to save a few days coding lol

like image 578
redhotspike Avatar asked Apr 18 '12 15:04

redhotspike


2 Answers

Your Java version of SimpleClass should do two things. One, keep a private long value that stores the value of the C++ pointer to the backing native object (you might have to use BigInteger depending on how large a native pointer can be - unsigned long long?). Two, make the public methods (e.g. setIntVal) native.

public class SimpleClass {
    private long nativePtr;

    public SimpleClass() {
        nativePtr = initNativeSimpleClass();
    }

    public void destroy() {
        destroyNativeSimpleClass();
        nativePtr = 0L;
    }

    protected void finalize() throws Throwable {
        destroyNativeSimpleClass();
        nativePtr = 0L;
    }

    public native int getIntVal();
    public native void setIntVal(int val);

    private native long initNativeSimpleClass();
    private native void destroyNativeSimpleClass();
}

Then implement those native methods in your JNI code. The initNativeSimpleClass() method will new a backing C++ instance of SimpleClass. The destroyNativeSimpleClass() method will then delete that instance. The accessor methods will use the value of nativePtr, cast it to a real pointer, and perform the appropriate operations on the native backing instance.

This idiom poses a real risk of leaking memory because users of the class MUST call destroy when they are done with an instance. If they don't, the backing native instance may not be properly destroyed. You can, as I've shown in the example, override finalize to call the native destroyer function, but all the caveats about how finalize can't be relied on still apply. By setting the nativePtr value to 0 upon destruction you avoid seg faults if destroy is called multiple times (it's safe in C++ to delete NULL).

like image 110
pedorro Avatar answered Oct 06 '22 00:10

pedorro


No you can't. The C++ and Java ABIs are completely different - for one, c++ doesn't define one. And really c++ has so many features that can't be mapped to Java at all this just can't work. How do you expect Java would handle c++ templates? Pointers to primitives? Objects that aren't pointers?

Now what you can do, is use SWIG to generate the right wrapper methods for you - that will actually work and is not much more work than what you planned :)

like image 30
Voo Avatar answered Oct 06 '22 00:10

Voo