Question
How can I return an ArrayList of Strings from Java to JNI?
JNIEXPORT jobject JNICALL Java_MyClass_getStringList(JNIEnv *env, jobject obj) {
// Create a new Java ArrayList
jclass arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
jmethodID arrayListInit = (*env)->GetMethodID(env, arrayListClass, "<init>", "()V");
jobject arrayList = (*env)->NewObject(env, arrayListClass, arrayListInit);
// Add Strings to the ArrayList
jmethodID arrayListAdd = (*env)->GetMethodID(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
jstring str1 = (*env)->NewStringUTF(env, "Hello");
(*env)->CallBooleanMethod(env, arrayList, arrayListAdd, str1);
jstring str2 = (*env)->NewStringUTF(env, "World");
(*env)->CallBooleanMethod(env, arrayList, arrayListAdd, str2);
// Return the ArrayList
return arrayList;
}
Answer
JNI provides a way for Java code to call and be called by native applications and libraries written in other languages such as C and C++. Returning an ArrayList of Strings from native code back to a Java application involves creating an ArrayList instance and adding elements to it through JNI calls.
JNIEXPORT jobject JNICALL Java_MyClass_getStringList(JNIEnv *env, jobject obj) {
// Create a new Java ArrayList
jclass arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
jmethodID arrayListInit = (*env)->GetMethodID(env, arrayListClass, "<init>", "()V");
jobject arrayList = (*env)->NewObject(env, arrayListClass, arrayListInit);
// Add Strings to the ArrayList
jmethodID arrayListAdd = (*env)->GetMethodID(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
jclass stringClass = (*env)->FindClass(env, "java/lang/String");
jstring str1 = (*env)->NewStringUTF(env, "Hello");
(*env)->CallBooleanMethod(env, arrayList, arrayListAdd, str1);
jstring str2 = (*env)->NewStringUTF(env, "World");
(*env)->CallBooleanMethod(env, arrayList, arrayListAdd, str2);
// Return the ArrayList
return arrayList;
}
Causes
- Understanding JNI conventions
- Properly managing Java objects from native code
- Using the right method IDs to interact with Java classes
Solutions
- Use the JNI API correctly to access Java class methods and constructors.
- Manage the local references to prevent memory leaks in JNI.
Common Mistakes
Mistake: Not releasing local references, leading to memory leaks.
Solution: Use DeleteLocalRef() after you're done with each local reference.
Mistake: Incorrectly calling Java methods leading to exceptions at runtime.
Solution: Check for exceptions using env->ExceptionCheck() and env->ExceptionDescribe() after native calls.
Helpers
- JNI
- Java Native Interface
- ArrayList
- C code
- return Java objects from JNI
- Java to JNI
- JNI ArrayList example