JNI - сопоставление типа UChar с

У меня есть функция JNI, которая возвращает массив UChar (из библиотеки ICU4C), который я хотел бы преобразовать в массив символов Java, чтобы я мог вызывать это из Java. Я не уверен, в чем проблема, так как всякий раз, когда я обращаюсь к этой функции JNI, все падает и зависает, но я нигде не получаю сообщения об ошибке, в том числе в логарифме... очень сложно отлаживать!

Может ли массив 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);

}

Любая помощь приветствуется!

Спасибо


person Ayyoudy    schedule 15.02.2011    source источник
comment
Пробовали ли вы подключить отладчик к работающему процессу Java, который вызывает код JNI, поставить точку останова на первой строке и пройти через нее?   -  person Timo Geusch    schedule 15.02.2011
comment
Здесь недостаточно кода, чтобы найти проблему. Как выглядит конец java? По какой причине вы не используете GetArrayLength? Работает ли привязка, иначе ведет себя эта функция, если она просто возвращает 0?   -  person Erik    schedule 15.02.2011
comment
Код выглядит нормально, если предположить, что длина dstArray равна len (как отмечалось выше, здесь лучше использовать GetArrayLength). Я бы закомментировал строку dst[i] = str[i] и посмотрел, не падает ли она по-прежнему. Если это так, ваша проблема в другом.   -  person fadden    schedule 16.02.2011


Ответы (4)


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");
}
person Lawrence Dol    schedule 23.02.2011

Если вы намерены получить значение UChar* из ICU и вернуть строку в 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;
}

Пример, конечно, упрощен, но он должен иллюстрировать преобразование 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()));
}
person NuSkooler    schedule 20.06.2012

Какова длина dstArray? c++ не может проверять границы массива и с удовольствием портит память вашего процесса, если len больше, чем dstArray.length.

person josefx    schedule 15.02.2011

ICU4JNI активно не поддерживается, но вы можете просмотреть его в качестве примера вызов ICU4C из JNI. См. также магистраль ICU4JNI SVN.

person Steven R. Loomis    schedule 23.02.2011