1

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.

AwaX
  • 448
  • 3
  • 8
  • 19

2 Answers2

4

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.

Community
  • 1
  • 1
main--
  • 3,873
  • 1
  • 16
  • 37
  • I didn't precise but yes I want the primitive type. I tried and it works fine with "[J" thank you. For the platform it will be both linux and windows, but what I need is just to be able to return values on 3 bytes minimum, so what is the best way to do that ? – AwaX Aug 02 '13 at 13:01
  • You could iterate over the second dimension instead of using the SetRegion function and cast the values entry by entry. That should work. – main-- Aug 02 '13 at 13:36
1

[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.

Tom Blodget
  • 20,260
  • 3
  • 39
  • 72
  • Yes what I want is the primitive type, but why do I have to change the return type ? – AwaX Aug 02 '13 at 13:03
  • Because `jlongArray` (`long[]`) is not the same as `jobjectArray` (`Long[]`). You can create a `jlongArray` with going through `FindClass`. See [NewLongArray](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp17318). – Tom Blodget Aug 02 '13 at 15:17
  • Sorry, I was thrown off by your use of "long array". You want return a C 2-D array of long. Java actually doesn't have multi-dimensional arrays. You have to return an array of arrays. The "inner" arrays can be `long[]`; the result is an object array. See @main--'s answer. – Tom Blodget Aug 03 '13 at 19:37