Search code examples
javac++vectorjava-native-interfacejnienv

NewDirectByteBuffer returning weird values


I have read many SO Q/A but I really can't get this to work. I need to work with a vector in C++ (a library needs it) in a JNI project. So I am calling a C++ method which initializes the vector and returns a pointer to the underlying array. Java is supposed to fill it, then call another C++ method to do elaboration. At the moment, to debug the code, doComputetion takes a ByteBuffer, but it won't later.

code is as following:

.cpp:

using namespace std;

JNIEXPORT jobject JNICALL Java_nnJNI_allocateStorage(JNIEnv * env, jobject obj, jint num)
{
vector<jfloat>* in = new vector<jfloat>(num, 40.0);
jobject jbuffer = env->NewDirectByteBuffer(in->data(), in->size() * sizeof(jfloat));
return env->NewGlobalRef(jbuffer); //I know this can be avoided
}

JNIEXPORT jobject JNICALL Java_nnJNI_doComputation(JNIEnv * env, jobject, jobject in)
{
float* f = (float*)env->GetDirectBufferAddress(in);
float* out = new float[1];
out[0] = 10;
jobject jbuffer = env->NewDirectByteBuffer(out, 1 * sizeof(jfloat));
return jbuffer;
}

java class:

public class nnJNI {
static {
    System.loadLibrary("YIAnnLib");
}

private native ByteBuffer allocateStorage(int size);

private native ByteBuffer doComputation(ByteBuffer buffer);

public void demo() {
    ByteBuffer buf = allocateStorage(2);
    float f = buf.getFloat();
    ByteBuffer b = ByteBuffer.allocateDirect(8);
    b.putFloat(10); b.putFloat(12);
    ByteBuffer res = doComputation(b);
    float g = res.getFloat();
}
}

As you can see I initialize the array with value 40.0. In Java, float f is everything but 40.0. I really can't understand what's wrong: no one is gonna free the vector declared with new. It should stay there. I noticed a strange thing: when allocating in C++, if I declare the vector on the stack as static it seems to work. Obiviously I won't do such a bad thing.

Also the opposite doesn't work: float *f in doComputation in C++ is everything but 10 (the value it should has as initilized in Java).

Obiviously float g in Java is everything but 10. It simulates data returned by the computation.

Any hints are really appreciated.


Solution

  • Thanks @cubrr . It was the endianness. Just call

     buf.order(ByteOrder.LITTLE_ENDIAN) 
    

    before reading and writing values IN Java. I guessed it, but I found nothing about it around, so I guessed it was automatically set according to the Operating System. It is not.