2

I have need to pass List of Strings from Java to C through JNI. My Java program pass a List argument and C program accepts a list.

Below is the code which I tried.

JNIEXPORT jobject JNICALL Java_jni_CallJNIfunction(JNIEnv *env,  
                                                         jobjectArray jParameters){

    list<const char*> cParameters;

    jsize stringCount = env->GetArrayLength(jParameters);

    for (int i=0; i<stringCount; i++) {
       jstring arrElement = (jstring) (env->GetObjectArrayElement(jParameters, i));
       const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);

       cParameters.push_back(nativeElement);
       env->ReleaseStringUTFChars(arrElement, nativeElement);
    }

    CallCfunction(cParameters);

}

But my JVM crashes at GetStringUTFChars() line. What is the wrong with this program?

1
  • 1
    When you say that you pass a List of arguments, do you really mean an array? The C function seems to be written to accept an array, and if Java passes a List object, you can expect it to crash at some point. Commented Oct 16, 2012 at 7:32

3 Answers 3

2

You do:

const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);
cParameters.push_back( nativeElement );
env->ReleaseStringUTFChars(arrElement, nativeElement);

You release the strings you store into a list, so your list contains a lot of bad pointers!

You must copy the string into a long time allocated space, you have the choice between std::string, char*+malloc, or use-it-and-forget-it approach.

Explanation for the third solution :

for( int i = 0; i < stringCount; ++i )
{
   jstring arrElement = (jstring) (env->GetObjectArrayElement(jParameters, i));
   const char* nativeElement = env->GetStringUTFChars( arrElement, NULL);
   CallCfunction( nativeElement ); // modified to process an item not a list<
   env->ReleaseStringUTFChars(arrElement, nativeElement);
}
Sign up to request clarification or add additional context in comments.

Comments

0

The following code will take a Set<String> and convert it into a std::vector<std::string>, but I wouldn't do this, you'd be better off converting the set to an array using the toArray method on the Set, you can then use your original code.

JNIEXPORT jobject JNICALL Java_jni_CallJNIfunction(
  JNIEnv *env,
  jclass,
  jobject setObj) {

    jmethodID iteratorID = env->GetMethodID(env->FindClass("java/util/Set"), "iterator", "()Ljava/util/Iterator;");
    jclass iterator = env->FindClass("java/util/Iterator");
    jmethodID hasNextID = env->GetMethodID(iterator, "hasNext", "()Z");
    jmethodID nextID = env->GetMethodID(iterator, "next", "()Ljava/lang/Object;");

    std::vector<std::string> strSet;

    jobject iteratorObj = env->CallObjectMethod(setObj, iteratorID);
    while (env->CallBooleanMethod(iteratorObj, hasNextID) == JNI_TRUE) {
      jstring current = (jstring)env->CallObjectMethod(iteratorObj, nextID);
      const char* str = env->GetStringUTFChars(current, NULL);

      strSet.push_back(str);

      env->ReleaseStringUTFChars(current, str);
    }
}

But unless you've got a massive Set which copying to an array would be too slow or take too much memory, then I would convert to an array.

Comments

0

The first answer in plain simple C-function is:

char **GetStringsfromJniStringArray(JNIEnv *env, jobjectArray stringArray) {
    size_t stringCount = (size_t)(*env)->GetArrayLength(env, stringArray);
    char **Strings=calloc(stringCount, sizeof(char*));
    int i = 0;
    for(i = 0; i < (int)stringCount; ++i )
    {
        jstring jniString = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
        const char *TempString = (*env)->GetStringUTFChars(env, jniString, NULL);
        Strings[i] = calloc(strlen(TempString)+1, sizeof(char));
        strcpy(Strings[i], TempString);
        (*env)->ReleaseStringUTFChars(env, jniString, TempString);
    }
    return Strings;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.