Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manipulation of ByteBuffer from JNI

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.

like image 755
gonzus Avatar asked Jul 04 '12 12:07

gonzus


People also ask

How do you make a ByteBuffer?

A ByteBuffer is created via the the two static factory methods: allocate(int) this will allocate a HeapByteBuffer with the capacity specified by the int argument. allocateDirect(int) this will allocate a DirectByteBuffer with the capacity specified by the int argument.

How does ByteBuffer work in Java?

ByteBuffer holds a sequence of integer values to be used in an I/O operation. The ByteBuffer class provides the following four categories of operations upon long buffers: Absolute and relative get method that read single bytes. Absolute and relative put methods that write single bytes.


1 Answers

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.

like image 162
maba Avatar answered Nov 15 '22 12:11

maba