How to pass a complex structure between C and Java with JNI on Android NDK

Bibu picture Bibu · Apr 24, 2012 · Viewed 16.4k times · Source

I have a complex strucutre in the C code on my Android application and I would like to use it in the Java side. I've done some research with google and in stackoverflow, so I've created the java class from my C strucutre, but now how to get it in Java.

I've found these informations, about making a pointer in the class and use this on the C side :

Get the field ID : (*env)->GetFieldID(...)
Get the pointer : (*env)->GetLongField(...)
Set the pointer : (*env)->SetLongField(...)

But I don't understand how it really works ...

Above, you can find what I've done until now ... not so much ! On the C side :

ComplexStructure Java_com_main_MainActivity_listenUDP(JNIEnv* env, jclass clazz)
{
    int i,taille;
    ComplexStructure myStruct;    
    taille = -1;    
    taille = recvfrom(socket, &myStruct, sizeof(ComplexStructure ), 0, &rcvAddr, &sizeOfSock);
    if(taille != -1)
    {   
        return myStruct;
    }
    return NULL;
}

And on the Java side :

public void getFromUDP() {

    ComplexClass myClass = new ComplexClass();
    myClass = listenUDP();              
}

@Override
public void run() {
    initUDP();
    getFromUDP();
}


public static native ComplexClass listenUDP();
public static native void initUDP();
public static native void closeUDP();

/** Load jni .so on initialization */
static {
     System.loadLibrary("native-interface");
}

EDIT : I want to add that my structure is very complex like that :

typedef struct{
  TYPE_A myStructA;
  TYPE_B myStructB;
  TYPE_C myStructC;
  TYPE_D myStructD;
}ComplexStructure;

typedef struct{
  float rad;
  int size;
  bool isEmpty;
}TYPE_A;

typedef struct{
  float rad;
  bool isEmpty;
  float color;
  int temp;
}TYPE_B;

typedef struct{
  int temp;
  float rain;
  bool isEmpty;
}TYPE_C;

typedef struct{
  float rad;
  int idPerson;
  bool isOnTime;
}TYPE_D;

Even more complex, just an example to show you how it is !

Answer

Jakub Zaverka picture Jakub Zaverka · Apr 24, 2012

You cannot pass raw C structs into Java and expect it to treat these structs as classes. You need to create a class for your struct. I see you already did that, so the only thing you need to do is to convert this struct into an instance of the class.

The code on the Java side:

public static native ComplexClass listenUDP();

will translate to:

JNIEXPORT jobject JNICALL Java_com_main_MainActivity_listenUDP(JNIEnv *env, jclass);

In that C code, you need to load the ComplexClass using the env->FindClass(); function. Then to create a new instance of that class (it simplifies matters if you have zero-parameter constructor), you need to load a constructor method signature and "invoke" it in the env->NewObject() method. Full code:

jclass complexClass = env->FindClass("/com/main/ComplexClass");
jmethod constructor = env->GetMethodId(complexClass, "<init>", "()com/main/ComplexClass"); //The name of constructor method is "<init>"
jobject instance = env->NewObject(complexClass, constructor);

Then you need to set the fields of this class using env->setXXXField();. If you have more objects as fields and want to alse create them, then repeat the above process for another object.

This looks very complicated, but that's the price for using native C in managed Java code.