0

I have a C function as follows:

int getInfo(int index, int type, void *pValue, int valueLen);

pValue is the address of the buffer to hold the information value. However, the buffer must have been allocated by the caller beforehand.

Since I am fairly certain that I am working with small data, I do the following in my Java managed code...

public native int callGetInfo(int index, int type, byte[] value);

...and then pass a fixed-size byte array like this:

byte[] buf = new byte[1024];
callGetInfo(idx, t, buf);

Reason is because I read that for small data, using a byte array is better than ByteBuffer in terms of performance.

My auto-generated JNI header is as follows:

JNIEXPORT jint JNICALL Java_com_testing_jni_Tester_callGetInfo (JNIEnv *, jobject, jint, jint, jbyteArray);

And so far this is what I have inside my bridging function:

JNIEXPORT jint JNICALL Java_com_testing_jni_Tester_callGetInfo (JNIEnv *env, jobject obj, jint index, jint type, jbyteArray array)
{
    jboolean isCopy;
    jbyte* bufferPtr = (*env)->GetByteArrayElements(env, array, &isCopy);

    // here I need to call the getInfo(index, type, pValue, valueLen) function, and then convert the pValue into a jbyteArray and return it using array

    if(isCopy) {
        (*env)->ReleaseByteArrayElements(env, array, bufferPtr, 0);
    }
    return 0;
}

Inside my bridging function, I would like to convert the value of pValue (whatever type it may be) that I get back from the getInfo function, into a jbyteArray so that I can return it to my Java caller. How can I achieve this?

user10931326
  • 787
  • 2
  • 8
  • 15

1 Answers1

1

The solution would be something like

JNIEXPORT jint JNICALL Java_com_testing_jni_Tester_callGetInfo
(JNIEnv *env, jobject obj, jint index, jint type, jbyteArray array)
{
    jboolean isCopy;

    jsize arrayLength = (*env)->GetArrayLength(env, array);
    jbyte* bufferPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
    if (! bufferPtr) {
        // got exception
        return 0;
    }

    jint rv = getInfo(index, type, bufferPtr, arrayLength);
    (*env)->ReleaseByteArrayElements(env, array, bufferPtr, 0);
    return rv;
}

There is also a call GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical that might not be usable because the contents of getInfo are not known - specifically when using these functions the getInfo function cannot execute any blocking system call or otherwise do a long-running operation.

The isCopy tells whether or not the locked array was copied or not. If it wasn't copied then the function is modifying the actual Java array directly. If it was a copy, then now that 1024 bytes of the buffer were copied to another place and will be copied back at the end of the function. It might be that you did not intend this to happen... Perhaps you'd want to use a byte buffer instead...

  • VG but you should use one of the JNI methods to print or log the exception. – user207421 Jul 29 '19 at 10:18
  • @user207421 hmm? The only sensible course of action is to let the exception being thrown – Antti Haapala -- Слава Україні Jul 29 '19 at 10:20
  • @AnttiHaapala I intend for the 1024 bytes of buffer to be used to store the result that `getInfo(...)` returns. Would `ByteBuffer` be a better implement for this, instead of `byte[1024]`? And how should I go about implementing it? – user10931326 Jul 30 '19 at 01:20
  • The problem is indeed that while byte[] might have better performance on java side it might possibly be sluggish in C . You want to monitor whether the iscopy is true or not :) – Antti Haapala -- Слава Україні Jul 30 '19 at 04:23
  • @AnttiHaapala thank you for your explanation. I have updated my work accordingly, and I have posted a related question on Code Review - https://codereview.stackexchange.com/questions/225180/production-ready-comparison-between-byte-array-and-bytebuffer. – user10931326 Jul 30 '19 at 07:54