JNI如何通过传递和接收对象?

3
我可以帮您翻译成中文。这段内容是关于IT技术的。在JAVA应用程序中,我想使用JNI将对象作为参数传递给C代码,并再次使用JNI从C代码接收对象到JAVA中。在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);
}

但是,在从 JNI 代码的 JAVA 端返回这些函数后,该方法显示异常,如下所示:
java.lang.ArrayIndexOutOfBoundsException
    at jlibfprint.JlibFprint.binary_image(Native Method)
    at jlibfprint.SampleRun.main(SampleRun.java:96)

即对象没有被正确处理,并且从JNI层没有返回任何内容。 但我不知道应该在JNI代码中做出什么改变才能返回正确的对象。
请给我建议任何解决方案。

参见:https://dev59.com/AG435IYBdhLWcg3wvy-_ - Trilarion
1个回答

1

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

你调用的SetByteArrayRegion()看起来正确——它紧随着所需大小的数组的创建。

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

另外,一种替代方法是使用GetByteArrayElements()ReleaseByteArrayElements(),它们可能返回指向Java用于数组的相同内存的指针。


谢谢。您能否举个例子解释一下我应该用什么来替换SetByteArrayRegion() - rachana
我认为你对SetByteArrayRegion()的调用没有任何错误。我的第一步将是验证传递给GetByteArrayRegion()的数组至少具有FP_PRINT_DATA_SIZE长度。在你让它工作之后,如果你认为避免复制数组很有用,这里有一些关于GetByteArrayElements/ReleaseByteArrayElements()的细节 - https://dev59.com/_Goy5IYBdhLWcg3wnPOJ 。 - Andy Thomas
我已经将FP_PRINT_DATA_SIZE的值设置为327680,与输入数组的大小相比,这已经足够了。 - rachana
它是否比输入数组的大小?如果它更大,您将在调用GetByteArrayRegion()时收到ArrayIndexOutOfBoundsException。如果您知道数组比FP_PRINT_DATA_SIZE小,则可以将GetByteArrayRegion()的第三个参数更改为输入数组的长度。更好的方法是请求FP_PRINT_DATA_SIZE和数组长度的最小值 - Andy Thomas
FP_PRINT_DATA_SIZE的值大于输入数组的大小。 - rachana
1
那么这就是问题所在。请参阅http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp6212:THROWS: ArrayIndexOutOfBoundsException:如果区域中的一个索引无效,则会抛出异常。 - Andy Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接