I am testing out direct ByteBuffer(java.nio.ByteBuffer) with JNI. So the code below tries to:
I was wondering where exactly did I do wrong? The C++ code manage to get the data from Java but changes in C++ did not reflect back in Java.
This is what I did on java:
public static void main(String[] args){
ByteBuffer bb = ByteBuffer.allocateDirect(3);
byte[] b = {122,121,120};
System.out.println("1: " + new String(b));
bb.put(b);
new JNI.process(bb);
byte[] c = new byte[3];
c[0] = bb.get();
System.out.println("4: " + new String(c));
}
This is what I did on JNI function:
JNIEXPORT void JNICALL Java_MarsJNI_mapreduce
(JNIEnv *env, jobject thisObj, jobject output){
char *out = (char*)env->GetDirectBufferAddress(output);
printf("2: %s\n", out);
out = "ABC";
printf("3: %s\n", out);
}
And the result I get is:
1: zyx
2: zyx
3: ABC
Exception in thread "main" java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:474)
at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:208)
at MarsJNI.main(MarsJNI.java:21)
First problem: see @TedBigham's answer. You can also use buf.rewind()
.
Second problem: you only copy the first byte of the buffer into c
, not the whole buffer. Do:
byte[] c = new byte[3];
bb.rewind();
bb.put(c);
System.out.println("4: " + new String(c));
Third problem: your C++ code does:
char *out = (char*)env->GetDirectBufferAddress(output);
// ...
out = "ABC";
But what you do here is create { 'A', 'B', 'C', 0 }
and assign out
to it; you don't actually modify the content of the buffer. You should do:
memcpy(out, "ABC", 3);
Fourth problem: when you create a String
out of a byte[]
, you should specify the encoding:
new String(c, StandardCharsets.UTF_8);