I need to call a Java API from C++, using JNI. I'm trying to pass a byte*
as below:
Java
void OperateData(byte[] data, int dataLength)
{
//Some Implementation
}
C++
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), (jobject)data, (jint)dataLength);
}
This is not working. It is throwing an exception. Can you please let me know what I am doing wrong?
Update: I modified the C++ code as below, based on suggestions. I'm still having the same issue. Is anything still wrong?
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
jbyteArray jBuff = jniEnv->NewByteArray(dataLength);
jniEnv->SetByteArrayRegion(jBuff, 0, dataLength, (jbyte*)data);
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jBuff, (jint)dataLength);
jniEnv->ReleaseByteArrayElements(jBuff,(jbyte*)data, 0);
}
You can't simply type-cast a raw C/C++ byte*
pointer into a jobject
representing a Java byte array. You need to use JNI functions to:
allocate a new Java byte array within the JVM's memory, via NewByteArray()
.
then copy your raw bytes into the memory of that Java array, via either:
GetByteArrayElements()
, memcpy()
, and ReleaseByteArrayElements()
then pass that Java array to your target Java method.
then finally release the Java array via DeleteLocalRef()
.
For example:
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
if (!methodObj) return;
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
if (!jniEnv) return;
jbyteArray jData = jniEnv->NewByteArray((jsize)dataLength);
if (!jData) return;
jniEnv->SetByteArrayRegion(jData, 0, (jsize)dataLength, (jbyte*)data);
jniEnv->CallVoidMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jData, (jint)dataLength);
jniEnv->DeleteLocalRef(jData);
}
Update: In comments, you say you changed the Java code to return a byte[]
instead of void
. If so, you need to adjust the C++ code accordingly, eg:
void OperateData(byte* data, int dataLength)
{
JavaMethod* methodObj = getMethod(_T("OperateData"));
if (!methodObj) return;
JNIEnv* jniEnv = JvmManager::GetInstance()->GetJNIEnv();
if (!jniEnv) return;
jbyteArray jData = jniEnv->NewByteArray((jsize)dataLength);
if (!jData) return;
jniEnv->SetByteArrayRegion(jData, 0, (jsize)dataLength, (jbyte*)data);
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), jData, (jint)dataLength);
if (jBuffer) jniEnv->DeleteLocalRef(jBuffer);
jniEnv->DeleteLocalRef(jData);
}