For some reason I have to use Linux-specific API which is not currently accessible from JVM directly and need to design a method which accepts ByteBuffer
(This is definitely not because of some performance reason). Here is how it looks like:
//I need to call device-specific ioctl here
//and fill the ByteBuffer
public static native long putIntoByteBuffer(int fd, ByteBuffer buf);
The generated header file is
JNIEXPORT jlong JNICALL Java_net_abcomm_PlatformSpecific_putIntoByteBuffer
(JNIEnv *, jclass, jint, jobject);
How to get the char*
by the given ByteBuffer
with JNI
? I could use DirectBuffer
, but then I will be limited to DirectBuffer
s only and besides the following warning is generated:
warning: DirectBuffer is internal proprietary API and may be removed in a
future release
import sun.nio.ch.DirectBuffer;
Also there is GetDirectBufferAddress
returning void*
but it is limited to DirectBuffer
s only.
Supposing that you limit yourself to public classes and their public API, you have two relatively efficient alternatives for approaching the problem, but they have in common that they rely on putting the data into a Java byte[]
. That's not so hard:
/* error checks omitted for brevity; these are *not* optional */
char *cBytes = /* ... */;
size_t numCBytes = /* ... */;
jbyteArray javaBytes = /* ... */;
jsize numBytes = (*env)->GetArrayLength(env, javaBytes);
jbyte *bytes = (*env)->GetPrimitiveArrayCritical(env, javaBytes, NULL);
/* It is pretty safe to assume that jbyte is a character type, such as signed
char, in any C implementation that supports the JNI at all */
/* Assumes numCBytes <= numBytes; adjust as necessary if that may not be true: */
memcpy(bytes, cBytes, numCBytes);
(*env)->ReleasePrimitiveArrayCritical(env, javaBytes, bytes, 0);
Note that if the JNI function performs some kind of I/O to get the bytes, it may be able to read them directly into bytes
(depending on the native requirements, not on JNI), but in that case you should use the non-Critical
versions of the Get
/Release
routines.
With that said, your two main alternatives for getting the data all the way into a ByteBuffer
are
if the buffer hasArray()
, then obtain the byte[]
for the above procedure via the buffer's array()
method. Done and done.
if the buffer does not hasArray()
, or if you don't want to check, then obtain the byte[]
by instantiating it freshly, and after loading it via the above procedure, copy the contents into the buffer via the buffer's bulk put(byte[])
or put(byte[], int, int)
method. Obviously, this involves an extra copy relative to the other alternative, and it uses an extra temporary object.
I cannot recommend assuming a specific concrete ByteBuffer
subclass or relying on non-public methods. That might be worth considering if performance were a high priority, but you seem to say it's not.