18

I need to pass a (direct) ByteBuffer to native functions that will read/write from/into the buffer. Once these operations are completed, I would like to access the ByteBuffer from Java code using the regular functions; in particular, limit() and position() should reflect the current state of the buffer.

Since JNI will use GetDirectBufferAddress() to directly access the underlying buffer, I am assuming I should call flip () / limit() / position() after I am done reading / writing. However, I have been unable to make this work. For example, after I read a couple of bytes into the buffer from C, and set its limit and position accordingly, I cannot query those bytes from Java; Java's idea of the buffer limit and position are not consistent with what I did in the C code.

Can anybody point me to a working example of this? Thanks in advance.

maba
  • 47,113
  • 10
  • 108
  • 118
gonzus
  • 181
  • 1
  • 1
  • 3
  • Should work, that's the whole idea. What position and limit values are you setting, and how, and what values for them are you seeing in Java? – user207421 Jul 05 '12 at 07:33

1 Answers1

19

You could let your native method return the number of written bytes. Then update the ByteBuffer accordingly on the Java side.

public class SomeClass {
    /**
     * @param buffer input/output buffer
     * @return number of bytes written to buffer
     */
    private native int nativeMethod(ByteBuffer buffer);

    public void myMethod() {
        ByteBuffer buffer = ByteBuffer.allocateDirect(100);
        int written = nativeMethod(buffer);
        if (written > 0) {
            buffer.limit(written);
        }
        ...
    }
}

Edit

Trying out to set the limit value on the C side is working too so I don't know why you have problems with it.

Naive implementation (nothing cached etc.):

static jint nativeMethod(JNIEnv *env, jobject obj, jobject buffer) {
    jclass cls = env->GetObjectClass(buffer);
    jmethodID mid = env->GetMethodID(cls, "limit", "(I)Ljava/nio/Buffer;");
    char *buf = (char*)env->GetDirectBufferAddress(buffer);
    jlong capacity = env->GetDirectBufferCapacity(buffer);
    int written = 0;

    // Do something spectacular with the buffer...

    env->CallObjectMethod(buffer, mid, written);
    return written;
}

The limit is set on the buffer when inspecting on Java side.

maba
  • 47,113
  • 10
  • 108
  • 118