【问题标题】:How to pass and receive objects using JNI如何使用 JNI 传递和接收对象
【发布时间】:2013-08-22 12:54:04
【问题描述】:

我有一个JAVA 应用程序,我想使用JNI 将对象作为参数传递给C 代码,并且我想再次使用C 代码将对象接收到JAVA JNI.

在 JAVA 方面,我只是创建了一个应用程序并将其传递给如下所示的方法

JlibFprint.fp_image_data fpimg = new JlibFprint.fp_image_data();   //object to be pass  
 //fp_image_data is the static inner class of the class JlibFprint

JlibFprint.fp_image_data fpimg1 = new JlibFprint.fp_image_data();   //received object

这个对象被传递给类似的方法

fpimg1 = JlibFprint.binary_image(fpimg);

该方法的JNI代码如下所示:

JNIEXPORT jobject JNICALL Java_jlibfprint_JlibFprint_binary_1image(JNIEnv *env, jclass jcls,jobject imgobj)
{
    struct fp_img img;
    struct fp_img *imgptr;
    imgptr = &img;
    jfp2cfp(env,imgobj,imgptr);     
    fp_init();
    imgptr = fp_img_binarize(imgptr);
    cfp2jfp(env, imgobj, imgptr);
    fp_exit();
    return imgobj;
}

void jfp2cfp(JNIEnv* env, jobject obj, fp_img *fpd)
{
    /* Determines all the fields of the object */
    jclass fpClass = env->FindClass("jlibfprint/JlibFprint$fp_image_data");
            jfieldID height;
            jfieldID width;
            jfieldID length;
            jfieldID data;
            jbyteArray dataArray;

            height = env->GetFieldID(fpClass, "height", "I");
            width = env->GetFieldID(fpClass, "width", "I");
            length = env->GetFieldID(fpClass, "length", "I");
            data = env->GetFieldID(fpClass, "data", "[B");

         /* Starts to fill fpd */
       fpd->height = env->GetIntField(obj, height);
        fpd->width = env->GetIntField(obj, width);
        fpd->length = env->GetIntField(obj, length);
        printf("\n height :%d",fpd->height);
        printf("\n width  :%d",fpd->width);
        printf("\n length :%d",fpd->length);
        dataArray = static_cast<jbyteArray>(env->GetObjectField(obj, data));
        env->GetByteArrayRegion(dataArray, 0, FP_PRINT_DATA_DATA_SIZE, (jbyte*)fpd->data);

}

void cfp2jfp(JNIEnv* env, jobject obj, fp_img* fpd)
{
    /* Determines all the fields of the object */
    jclass fpClass = env->FindClass("jlibfprint/JlibFprint$fp_image_data");
        jfieldID height;
        jfieldID width;
        jfieldID length;
        jfieldID data;

        jbyteArray dataArray;
        height = env->GetFieldID(fpClass, "height", "I");
        width = env->GetFieldID(fpClass, "width", "I");
        length = env->GetFieldID(fpClass, "length", "I");
        data = env->GetFieldID(fpClass, "data", "[B");

        /* Starts to fill the obj */
        env->SetIntField(obj, height, fpd->height);
        env->SetIntField(obj, width, fpd->width);
        env->SetIntField(obj, length, fpd->length);

        dataArray = env->NewByteArray(FP_PRINT_DATA_DATA_SIZE);
        env->SetByteArrayRegion(dataArray, 0, FP_PRINT_DATA_DATA_SIZE, (jbyte*)fpd->data);

        env->SetObjectField(obj, data, dataArray);
}

但是在JAVA端从JNI代码的这些函数返回后,该方法显示异常

java.lang.ArrayIndexOutOfBoundsException
    at jlibfprint.JlibFprint.binary_image(Native Method)
    at jlibfprint.SampleRun.main(SampleRun.java:96)

即对象未正确处理,它不会从 JNI 层返回任何东西。 但是我没有得到我应该在 JNI 代码中更改什么以便它返回正确的对象。

请给我建议任何解决方案。

【问题讨论】:

标签: java c exception exception-handling java-native-interface


【解决方案1】:

如果指定区域超出数组边界,GetByteArrayRegion()SetByteArrayRegion() 都可以抛出 ArrayIndexOutOfBoundsException。

您对 SetByteArrayRegion() 的调用看起来是正确的——它紧跟在创建所需大小的数组之后。

验证 GetByteArrayRegion() 访问的入口数组的大小至少为 FP_PRINT_DATA_DATA_SIZE。

顺便说一句,另一种方法是使用GetByteArrayElements()ReleaseByteArrayElements(),它们可能返回指向Java 用于数组的同一内存的指针。

【讨论】:

  • 谢谢。你能用例子解释一下我应该用什么来代替SetByteArrayRegion()
  • 您对 SetByteArrayRegion() 的调用没有任何错误。我的第一步是验证传递给 GetByteArrayRegion() 的数组是否至少具有 FP_PRINT_DATA_SIZE 长度。完成这项工作后,如果您认为避免复制数组很有用,这里有一些关于 GetByteArrayElements/ReleaseByteArrayElements() - stackoverflow.com/questions/8439233/… 的详细信息。
  • 我已将 FP_PRINT_DATA_SIZE 的值设置为 327680,与输入数组的大小相比已经足够了
  • 它是否比输入数组的大小?它更大,您将在调用 GetByteArrayRegion() 时收到 ArrayIndexOutOfBoundsException。如果您知道数组小于 FP_PRINT_DATA_SIZE,您可以将 GetByteArrayRegion() 的第三个参数更改为输入数组的长度。更好的是,请求 FP_PRINT_DATA_SIZE 的最小值和数组的长度。
  • 那就是问题所在。请参阅docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/…:抛出:ArrayIndexOutOfBoundsException:如果该区域中的索引之一无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 2018-01-19
  • 2017-01-16
  • 2011-11-07
相关资源
最近更新 更多