2011-02-15 94 views
0

我有一个JNI函数,它返回一个UChar数组(来自ICU4C库),我想将它转换为Java字符数组,以便可以从Java调用此函数。我不知道问题出在哪里,因为每当我访问这个JNI函数时,一切都崩溃并挂起,但我不会在任何地方发现错误消息,包括logcat中......非常难以调试!JNI - 映射UChar类型为

UChar数组可以直接映射到jcharArray类型吗?另外,我可以使用它作为返回类型吗?或者我可以将它作为JNI函数填充的参数传入?

下面是基本上我试图做一个片段:

static jint testFunction(JNIEnv* env, jclass c, jobject obj, jcharArray chsArray, 
          int offset, int len, jcharArray dstArray) { 

jchar* dst = env->GetCharArrayElements(dstArray, NULL); 

if (dst != NULL) { 

    UChar *str = new UChar[len]; 

    //populate str here from an ICU4C function 

    for (int i=0; i<len; i++) 
     dst[i] = str[i];  //this might be the problematic piece of code (can I issue an assignment like this?) 
    } 
} 

env->ReleaseCharArrayElements(dstArray, dst, 0); 

} 

任何帮助表示赞赏!

谢谢

+1

您已经尝试了调试器附加到正在运行的Java程序调用JNI代码,把一个断点在第一行,并通过它一步? – 2011-02-15 20:40:27

回答

1

JNI可能是一个真正的头痛。你的表面看起来很好看。

首先,我注意到你没有使用offset - 这是一种代码味道。

其次,你没有释放UChar阵列。

第三,C函数或赋值循环可能会溢出数组边界。


为了帮助定位突然崩溃这样的,我已经成功地与控制台一起使用的好醇派print声明。

首先我添加一个println方法我JNIGlobal类:

/** Print text or ASCII byte array prefixed with "JNI: ". Primarily for native code to output to the Java console. */ 
static public void println(Object val) { 
    if(val instanceof byte[]) { byte[] ba=(byte[])val; val=new String(ba,0,ba.length); } 
    System.out.println("JNI: "+val); 
    } 

然后,我添加一个对应方法我的C代码:

void println(JNIEnv *jep, byte *format,...) { 
    va_list        vap; 
    byte        txt[5001]; 
    jsize        txtlen; 
    jclass        eCls; 
    jint        mId; 
    jbyteArray       jText; 

    va_start(vap,format); vsprintf(txt,format,vap); va_end(vap); 
    txtlen=(long)strlen(txt); 

    if((eCls=(*jep)->FindClass(jep,"<your/package/here/JNIGlobal"))==0) { 
     printf("JNI: Global class not found (Error Text: %s)\n",txt); 
     return; /* give up */ 
     } 
    if((mId=(*jep)->GetStaticMethodID(jep,eCls,"println","(Ljava/lang/Object;)V"))==0) { 
     printf("JNI: Global println method not found (Error Text: %s)\n",txt); 
     return; /* give up */ 
     } 
    jText=(*jep)->NewByteArray(jep,txtlen); 
    (*jep)->SetByteArrayRegion(jep,jText,0,txtlen,(void*)txt); 
    (*jep)->CallStaticVoidMethod(jep,eCls,mId,jText); 
    } 

然后我打电话println(env,"Some formatted output")在每一行来源看它有多远。在我的环境(一个AS/400)中,当JVM在交互式运行期间崩溃时,我只剩下控制台 - 您可能希望在Java代码中添加一小段延迟,以确保在控制台消失之前看到输出。

因此,对于你,就像这样:

static jint testFunction(JNIEnv* env, jclass c, jobject obj, 
jcharArray chsArray, int offset, int len, jcharArray dstArray) { 

/**/println("** testFunction 1"); 
    jchar* dst = env->GetCharArrayElements(dstArray, NULL); 

/**/println("** testFunction 2"); 
    if (dst != NULL) { 
/**/println("** testFunction 3"); 
     UChar *str = new UChar[len]; 
/**/println("** testFunction 4"); 

     //populate str here from an ICU4C function 

/**/println("** testFunction 5"); 
     for (int i=0; i<len; i++) 
      dst[i] = str[i];  //this might be the problematic piece of code (can I issue an assignment like this?) 
     } 
/**/println("** testFunction 6"); 
    } 

    env->ReleaseCharArrayElements(dstArray, dst, 0); 
/**/println("** testFunction 7"); 
} 
0

dstArray有多长?如果len大于dstArray.length,C++将无法检查数组边界并高兴地破坏进程的内存。

0

ICU4JNI没有被主动维护,但是你可能会看到它的一个从JNI调用ICU4C的例子。另请参阅ICU4JNI SVN trunk

1

如果你的目的是为了得到一个ICU UCHAR *值,并返回一个字符串到Java(我基于“填充海峡从这里假定这ICU4C功能“评论),为什么不只是使用jstring

例如:

jstring Java_com_mysomethingsomething_test_getAString(JNIEnv* env, jobject thiz) 
{ 
    UChar* buf = new UChar[BUF_LEN]; 
    int32_t len; 
    PouplateBuffer(buf, &len);  //populate str here from an ICU4C function 
    jstring result = env->NewString(reinterpret_cast<jchar*>(buf), static_cast<jint>(len)); 
    delete [] buf; 
    return result; 
} 

该示例simplifed当然,但应说明UCHAR *到的jstring转换。这也很容易用的UnicodeString工作:

jstring Java_com_mysomethingsomething_test_getAString(JNIEnv* env, jobject thiz) 
{ 
    const UnicodeString result = PopulateString(); 
    return env->NewString(reinterpret_cast<jchar*>(result.getBuffer()), static_cast<jint>(result.length())); 
}