how to write and read from bytebuffer passing from java to jni
I don't use jni_onload, so no javah in C++
It may be irrelevant to your question, but you sort of have to do one or the other. You either need to do your Java-to-Native method mapping in the onLoad function or use javah to generate the method signatures that JNI can pick up at runtime. Otherwise your native methods will never be invoked.
If your native method is properly being called, however, whatever you are doing is probably fine.
I am stuck here, can I do double dbuf? or is it has to be a char?
The return value of the function is actually a void*
, so you can cast it to whatever pointer type you want since it is just a memory address. However, the actual data type of the direct buffer will be jbyte
, which is a typedef of signed char
, so the following is probably best:
jbyte *dBuf = env->GetDirectBufferAddress(env, buf);
Let said I want to write 1,2,3,4,5 to this dbuf, how do I do it?
The notation in C/C++ to access values in an array is with [] notations, i.e.:
jbyte *dBuf = env->GetDirectBufferAddress(env, buf);
dBuf[0] = 63;
dBuf[1] = 127;
// ...and so on...
and after populating it, do I just call bb.get(position) in java?
Yes, you can use the accessor methods on ByteBuffer
to access the data you have written from your native code.
Lan Nguyen
Updated on June 19, 2022Comments
-
Lan Nguyen almost 2 years
I need help with my android project. I want to pass a buffer from java to jni, and my C++ code will populate the data. Then java will display them on the screen. I am not familiar much with C++ and have no idea how to write to write to the buffer.
this is what i got. in java
ByteBuffer bb = ByteBuffer.allocateDirect(216); IssmJni.processBuffer(bb);
native method
public static native void processBuffer(ByteBuffer bb);
I don't use jni_onload, so no javah in C++
static void fillBuffer(JNIEnv *env, jclass clazz, jobject buf) { double *dBuf = env->GetDirectBufferAddress(env, buf); }
I am stuck here, can I do double dbuf? or is it has to be a char?
Let said I want to write 1,2,3,4,5 to this dbuf, how do I do it? i am thinking of dbuf.put(1); ... dbuf.put(5) but it is not working. and after populating it, do I just call bb.get(position) in java?
Someone clarify this for me please, example would be appreciated Thank you
this is my table of native methods
static JNINativeMethod method_table[] = {
{"fac" , "(J)J" , (void *) factorial}, {"getBuffer", "()[D" , (void *) getBufferNative}, //{"processBuffer", "(Ljava/nio/ByteBuffer)V", (void *) fillBuffer}};
The other two works fine except the last one.
-
Lan Nguyen over 11 yearsty, it works,but I have 2 questions. First, as far as I know this is shared memory right. The reason that I am doing this is because the data will be huge and I do not want to marshaling the data every time passing back and forth. Second how do i make this jni_onload, I am using javah right now. For onload I tried this, {"processBuffer", "(Ljava/nio/ByteBuffer)V", (void *) fillBuffer} , processBuffer is native method from java, Ljava/nio/ByteBuffer this is the parameter bytebuffer, V refer to void, fillBuffer refers to C++ function. But it not mapping correctly, can you check it please, thanks
-
devunwired over 11 yearsYes, the direct buffer is accessed on both sides without copying memory; that is why you don't have to pass the object back from native code.
-
Lan Nguyen over 11 yearsthanks, very informative. What about the second question Devu, can you see what I did wrong? thanks
-
devunwired over 11 yearsI think your method signature should be
"(Ljava/nio/ByteBuffer;)V"
instead...with a semicolon after the class name. The rest looks correct to me. -
Lan Nguyen over 11 yearsIf you look at the table I just did above the other two method doesn't have semicolon so, it is kinda weird isn't it. Yes the 2 fac, and getbuffer work perfectly fine. One more thing, I did this dBuf[0] = 10.67; and in java it returns 1.300779E-258. How come, I use bb.getDouble().
-
devunwired over 11 yearsThe semicolon is only required on qualified Java class names, not primitives. Have a look here: dev.kanngard.net/Permalinks/ID_20050509144235.html
-
devunwired over 11 yearsThe conversion issue is with types. Your buffer is an array of bytes, and it takes eight bytes (64 bits) to make up a double. So when you call
getDouble()
it takes the data from dBuf[n] through dBuf[n+7] to construct the value. You can read more about floating point types here: docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3 I'm not a C++ expert, you may be able to cast the buffer return as a (double*) for easier insertion. Otherwise you will need to convert each double to bytes in native code first. -
Lan Nguyen over 11 yearsDoubleBuffer buff = ByteBuffer.allocateDirect(15*8).asDoubleBuffer(); this works perfectly Devu, and putting semicolon works too thanks alot. Devu if you happen to know about native thread in jni please shoot me the link. I want to have a method from java that fire a native thread in JNI and communicate between main java thread and jni thread. Example would be awesome
-
devunwired over 11 yearsI'd post a new question for that because it's a bit outside my expertise.
-
Lan Nguyen over 11 yearsHi Devu, I have this new problem, don't know if you can help. let say I have a C++ code that create class call hello and in that class has method called print and return string helloworld. If the UI side hit a button, it will called this print method, but I want to create only 1 object hello, and use the same print method instead of creating new object hello every time. I know I need to save the object as global reference, but how would you reference to it next call, if you know can you give me example code. Thanks,
-
devunwired over 11 yearsI think you should post these as new questions so others with experience will see them.
-
Lan Nguyen over 11 yearsI solved the previous one, ty tho. I am having this idea, but not sure if it is possible. Instead of passing in a DoubleBuffer. I want to pass in a DoubleBuffer[]. Jni side still does the data allocation. Will this be possible? can I say jdouble *dBuf = env->GetDirectBufferAddress(env, buf[i]) where i is the index of the array, or jdouble **dbuf since this is 2D thing and access by dbuf[i][j].
-
Deepak over 9 yearsIm getting following problem, How i can get JNIEnv problems please help me : env->GetDirectBufferAddress(env, buffer);