1

I think I have an idea of what to do, I just wanted to poke the SO community to see if I'm on the right track as I haven't seen any information about this specific topic from my research.

I have some custom Java (data model) classes that I want to be accessible on my native C++ side of my application. I realize that these two environments are fairly separate, so I'll have to most likely create a "copy" of my data models in c++, and initialize them in my nativeLib JNI file?

I'm assuming I can't just "convert" the java class to the c++ class, since the compiler probably won't be able to do such a conversion. I'll have to manage each of the fields that I need manually through a JNI method call.

Is this correct, or is there a better way that I'm not aware of?

I suppose an example might look like this:

Foo.java

public class Foo {
    boolean A;
    boolean B;
    boolean C;
}

native-lib.cpp

extern "C" {

    std::unique_ptr<Foo> foo;

    JNIEXPORT void JNICALL
    Java_com_example_user_project_native_1Foo(JNIEnv *env, jobject instance, jbool jbooleanA, jbool jbooleanB, jbool jbooleanC) {

    Foo->setA(jbooleanA);
    Foo->setB(jbooleanB);
    Foo->setC(jbooleanC);
}

Foo.h

class Foo {
private:
    bool A;
    bool B;
    bool C;

public:
    // add setters & getters here, or any other needed functions
}
Matt Strom
  • 698
  • 1
  • 4
  • 23

2 Answers2

0

I'm assuming I can't just "convert" the java class to the c++ class, since the compiler probably won't be able to do such a conversion.

You are right in your assumption. If you seek automation of proxifing classes between native and Java, take a look at SWIG. It is able to scan a header file and build a wrapper (.cpp + .java) code that exposes the native class to JVM. This is not exactly what you are asking about, but may be very close.

Alexander Solovets
  • 2,447
  • 15
  • 22
0

While finding the solution to my question, I found out more specifics to why the conversion doesn't work:

  1. ArrayList (from Java) is not perceived as a jobjectArray in the JNI framework. It is recognized as a jObject. So if you wanted to convert an ArrayList object you would have to create a new jobjectArray in JNI

  2. You cannot access methods from the ArrayList class (like get, or set), as the class of the parameters is a generic. Generics aren't allowed in JNI

Because of these two reasons, an ArrayList object cannot be converted and sent through JNI. Instead I chose to convert my ArrayList into an object array myClass[] on the Java side, then send that through.

Bellow is the code I wrote for this conversion:

javaClass.java

void setFooArray(ArrayList<Foo> param) {
    Foo[] fooArray = new Foo[param.size()];

    for (int i = 0; i < param.size(); i++) {
        fooArray[i] = param.get(i);
    }

    native_setFooArray(fooArray, fooArray.length);
}

// ...

private native void native_setFooArray(Foo[] fooArray, int size);

native-lib.cpp

JNIEXPORT void JNICALL
java_com_example_my_project_native_1setFooArray(JNIEnv *env, jobject instance, jobjectArray fooArray, jint arraySize) {

    std::vector<Foocpp> cfooArray;

    jfieldID fidA;
    jfieldID fidB;

    for (jint i = 0; i < arraySize; i++) {
        jobject jfoo = env->GetObjectArrayElement(fooArray, i);
        jclass cfoo = env->GetObjectClass(jfoo);

        fidA = env->getFieldID(cfoo, "A", "I");
        fidB = env->GetFieldID(cfoo, "B", "I");
        jint A = env->GetIntField(cfoo, fidA);
        jint B = env->GetIntField(cfoo, fidB);

        const Foocpp foo = Foocpp(A, B);
        cfooArray.push_back(foo);
    }

    class->setFooArray(cfooArray);

Useful links:

Matt Strom
  • 698
  • 1
  • 4
  • 23