tags:

views:

757

answers:

1

I have an unsigned char* in my C library, and Im calling a JNI exported function that needs to set a java object with this data... preferably in a byte[].

But this function will be called very often, and it's quite a lot of data to be copied.. Is it possible to use a ByteBuffer and assign the pointer of that bytebuffer to my unsigned char*? Or does it only work the other way round

Can I even do this without copying the data? What would be the best way to access it? Thanks

edit: The size of the data in the unsigned char* is known.

+2  A: 

Here is a possible solution considering the small of information you gave.

On the Java side of things, you would have:

package com.stackoverflow;

public class JNIQuestion
{
  static native void fillByteArray(byte[] buffer);
}

And on the C side you would have:

JNIEXPORT void JNICALL Java_com_stackoverflow_JNIQuestion_fillByteArray(JNIEnv* env, jbyteArray array)
{
  jboolean isCopy;
  jbyte* buffer = (*env)->GetByteArrayElements(env, array, &isCopy);
  jsize length = (*env)->GetArrayLength(env, array);
  jsize i;

  // do something with the buffer here, replace with something meaningful
  // PAY ATTENTION TO BUFFER OVERFLOW, DO NOT WRITE BEYOND BUFFER LENGTH
  for (i = 0; i < length; ++i)
    buffer[i] = i;

  // here it is important to use 0 so that JNI takes care of copying
  // the data back to the Java side in case GetByteArrayElements returned a copy
  (*env)->ReleaseByteArrayElements(env, buffer, 0);
}

Using a direct ByteBuffer (ByteBuffer.allocateDirect()) is also a possible solution. However I only use a direct ByteBuffer when I need to fill data from the Java side a very precise offsets in the buffer.

About performance, the solution using a byte[] should be satisfactory as the JVM is likely to pin the byte array instead of copying it when invoking GetByteArrayElements().

Generally speaking, you will want to minimize the number of JNI calls which implies that accessing object fields from the C side or allocating Java from the C side will have an impact on performance.

In any case, profile first, optimize next.

PS: I didn't try to compile the code, there might be typos. Refer to the JNI Guide and the JNI Tutorial.

Gregory Pakosz
This comes close, but how do I grab a jbyteArray from a jobject?
John
you don't need to; do that from the Java side: `JNIQuestion.fillByteArra(myObject.getByteArray());` accessing object fields from the C side costs more.
Gregory Pakosz
This is not an option, I need to copy the data from my C lib due to event/queue based structures... It's not like the data will always be there.
John
I'm sorry I can't speculate more on what you're trying to achieve. See http://java.sun.com/docs/books/jni/html/fldmeth.html#30289 for how to access fields
Gregory Pakosz
I pass an object as parameter to my JNIEXPORTed function. That object has a public byte[] variable. I just need to copy data from a local C structure into that byte[] from within that JNI function, that's all
John
then you might want to pass your object to your native function and from the JNI side of things you access the field, refer to the link in my previous comment for a tutorial :)
Gregory Pakosz