Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access arrays within an object with JNI?

JNI tutorials, for instance this one, cover quite well how to access primitive fields within an object, as well as how to access arrays that are provided as explicit function arguments (i.e. as subclasses of jarray). But how to access Java (primitive) arrays that are fields within an jobject? For instance, I'd like to operate on the byte array of the following Java object:

class JavaClass {   ...   int i;   byte[] a; } 

The main program could be something like this:

class Test {    public static void main(String[] args) {     JavaClass jc = new JavaClass();     jc.a = new byte[100];     ...     process(jc);   }    public static native void process(JavaClass jc); } 

The corresponding C++ side would then be:

JNIEXPORT void JNICALL Java_Test_process(JNIEnv * env, jclass c, jobject jc) {    jclass jcClass = env->GetObjectClass(jc);   jfieldID iId = env->GetFieldID(jcClass, "i", "I");    // This way we can get and set the "i" field. Let's double it:   jint i = env->GetIntField(jc, iId);   env->SetIntField(jc, iId, i * 2);    // The jfieldID of the "a" field (byte array) can be got like this:   jfieldID aId = env->GetFieldID(jcClass, "a", "[B");    // But how do we operate on the array??? } 

I was thinking to use GetByteArrayElements, but it wants an ArrayType as its argument. Obviously I'm missing something. Is there a way to to this?

like image 518
Joonas Pulakka Avatar asked Jul 06 '09 11:07

Joonas Pulakka


People also ask

How do I return an array in JNI?

If you just wanted to return a single dimensional array of ints, then the NewIntArray() function is what you'd use to create the return value. If you wanted to create a single dimensional array of Strings then you'd use the NewObjectArray() function but with a different parameter for the class.

What is Jclass in JNI?

typedef jobject jclass; In C++, JNI introduces a set of dummy classes to enforce the subtyping relationship. For example: class _jobject {}; class _jclass : public _jobject {}; ...

What is JNI Jobject?

jobject thiz means the this in java class. Sometimes if you create a static native method like this. void Java_MyClass_method1 (JNIEnv *, jclass); jclass means the class itself. Follow this answer to receive notifications.


Video Answer


1 Answers

I hope that will help you a little (check out the JNI Struct reference, too):

// Get the class jclass mvclass = env->GetObjectClass( *cls ); // Get method ID for method getSomeDoubleArray that returns a double array jmethodID mid = env->GetMethodID( mvclass, "getSomeDoubleArray", "()[D"); // Call the method, returns JObject (because Array is instance of Object) jobject mvdata = env->CallObjectMethod( *base, mid); // Cast it to a jdoublearray jdoubleArray * arr = reinterpret_cast<jdoubleArray*>(&mvdata) // Get the elements (you probably have to fetch the length of the array as well double * data = env->GetDoubleArrayElements(*arr, NULL); // Don't forget to release it  env->ReleaseDoubleArrayElements(*arr, data, 0);  

Ok here I operate with a method instead of a field (I considered calling a Java getter cleaner) but you probably can rewrite it for the fields as well. Don't forget to release and as in the comment you'll probably still need to get the length.

Edit: Rewrite of your example to get it for a field. Basically replace CallObjectMethod by GetObjectField.

JNIEXPORT void JNICALL Java_Test_process(JNIEnv * env, jclass c, jobject jc) {    jclass jcClass = env->GetObjectClass(jc);   jfieldID iId = env->GetFieldID(jcClass, "i", "I");    // This way we can get and set the "i" field. Let's double it:   jint i = env->GetIntField(jc, iId);   env->SetIntField(jc, iId, i * 2);    // The jfieldID of the "a" field (byte array) can be got like this:   jfieldID aId = env->GetFieldID(jcClass, "a", "[B");    // Get the object field, returns JObject (because Array is instance of Object)   jobject mvdata = env->GetObjectField (jc, aID);    // Cast it to a jdoublearray   jdoubleArray * arr = reinterpret_cast<jdoubleArray*>(&mvdata)    // Get the elements (you probably have to fetch the length of the array as well     double * data = env->GetDoubleArrayElements(*arr, NULL);    // Don't forget to release it    env->ReleaseDoubleArrayElements(*arr, data, 0); } 
like image 104
Daff Avatar answered Sep 25 '22 13:09

Daff