AwaX
AwaX

Reputation: 588

How to return 2D long array with JNI

I'm writing a code which must return a long array from C to java using JNI. But the method (*env)->FindClass returns NULL whatever I tried.

Here is my code :

// Returns a 2D long array from C to Java
JNIEXPORT jobjectArray JNICALL Java_awax_tools_AcquisitionWrapper_startAcquisition (JNIEnv *env, jobject obj) {

    // (...) Acquisition code

    // The 2D long array to return
    long** primitive2DArray = data;

    // Get the long array class
    jclass longArrayClass = (*env)->FindClass(env, "[java/lang/Long");

    // Check if we properly got the long array class
    if (longArrayClass == NULL) {
        // Ooops
        return NULL;
    }

    // Create the returnable 2D array
    jobjectArray myReturnable2DArray = (*env)->NewObjectArray(env, (jsize) length1D, longArrayClass, NULL);

    // Go through the firs dimension and add the second dimension arrays
    for (unsigned int i = 0; i < length1D; i++) {
        jlongArray longArray = (*env)->NewLongArray(env, length2D);
        (*env)->SetLongArrayRegion(env, longArray, (jsize) 0, (jsize) length2D, (jlong*) primitive2DArray[i]);
        (*env)->SetObjectArrayElement(env, myReturnable2DArray, (jsize) i, longArray);
        (*env)->DeleteLocalRef(env, longArray);
    }

    // Return a Java consumable 2D long array
    return myReturnable2DArray;
}

I also tried with :

(*env)->FindClass(env, "[L")
(*env)->FindClass(env, "[Long")
(*env)->FindClass(env, "[java.lang.Long")

But none of them seems to work.

Upvotes: 1

Views: 3732

Answers (2)

main--
main--

Reputation: 3973

If you really want an array of java.lang.Long objects, you have to write [Ljava/lang/Long;. If you create an array of those, you get [[Ljava/lang/Long; which would be Long[][] on the Java side.

However, this is terribly inefficient. You have to create an object for every single number inside that array. Using Long.valueOf can give you cached objects but I doubt that many values inside that array fit into a signed byte.

Instead of Long objects, you should use primitive long values. Everything except the first line of your code is already doing that. The correct internal name for an array of primitive longs is [J:

jclass longArrayClass = (*env)->FindClass(env, "[J");

The rest of your code is correct and the method will return a long[][].


But watch out: You aren't saying anything about which platform you're using, but on Windows for example, this still won't work: A long there is just an int in disguise, it's also a 32 bit value. A jlong on the other hand always has 64 bits and is typedef'd to a long long for exactly that reason. You're blindly casting the pointers, so your code would try to copy twice as much data as you actually have.

Upvotes: 4

Tom Blodget
Tom Blodget

Reputation: 20812

[java/lang/Long should be written as [Ljava/lang/Long; and refers to a type, not a class.

The class is Ljava/lang/Long;, which consistent with what NewObjectArray requires—the class for the elements:

jobjectArray NewObjectArray(JNIEnv *env, jsize length,
jclass elementClass, jobject initialElement);

BTW—Java does support primitive long arrays, which might be faster or simplier if you can change your native method return type.

Upvotes: 1

Related Questions