JNI Java包装器:如何传递byte []参数

时间:2018-07-11 02:04:33

标签: java c++ java-native-interface

我需要使用JNI从C ++调用Java API。我正在尝试通过byte*,如下所示:

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);
}

这不起作用。它引发了异常。您能告诉我我在做什么错吗?

更新:我根据建议修改了C ++代码,如下所示。我仍然有同样的问题。还是有问题吗?

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);
}

2 个答案:

答案 0 :(得分:4)

JavaMethod* methodObj = getMethod(_T("OperateData"));
// ...
jobject jBuffer = jniEnv->CallObjectMethod(m_javaObject->getJObject(), methodObj->getJMethodID(), (jobject)data,(jint)dataLength);
// ...
jniEnv->ReleaseByteArrayElements(jBuff,(jbyte*)data, 0);

这些都没有道理。

  1. JNI方法签名包含参数和返回类型信息,如javap -s的输出所给。因此,Java方法的JNI签名绝对不只是"OperateData"
  2. 因此您的methodObj必须为空,或包含为零的jmethodID,仅此一项就足以解释您的问题。
  3. 此代码中缺乏令人震惊的错误检查。 每个 JNI调用的结果都必须经过错误检查。
  4. 您正在调用的Java方法是void,因此它不会返回jobject
  5. 您要调用的Java方法是void,因此您应该使用CallVoidMethod()
  6. 您需要使用char *data将C ++ jbytearray数组转换为NewByteArray(),并使用适当的JNI Array Methods进行填充。
  7. 您打错了ReleaseByteArrayElements()。您不需要在这里完全调用它,但是当您调用它时,将使用通过GetByteArrayElements()获得的指针来调用它。没有您自己的数据。
  8. 通话结束后,您应该delete the local reference to the jbytearray

答案 1 :(得分:4)

您不能简单地将原始C / C ++ byte*指针类型转换为表示Java字节数组的jobject。您需要use JNI functions进行以下操作:

例如:

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);
}

更新:在注释中,您说您更改了Java代码以返回byte[]而不是void。如果是这样,则需要相应地调整C ++代码,例如:

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);
}