Skip to content

Instantly share code, notes, and snippets.

@qh-huang
Last active October 20, 2023 08:54
Show Gist options
  • Save qh-huang/6e43fb2311ee3c31752e11a4415deeb1 to your computer and use it in GitHub Desktop.
Save qh-huang/6e43fb2311ee3c31752e11a4415deeb1 to your computer and use it in GitHub Desktop.
JNI useful code pieces
// ==================== pull from Facebook/rockdb@github ====================
class ListJni {
public:
// Get the java class id of java.util.List.
static jclass getListClass(JNIEnv* env) {
jclass jclazz = env->FindClass("java/util/List");
assert(jclazz != nullptr);
return jclazz;
}
// Get the java class id of java.util.ArrayList.
static jclass getArrayListClass(JNIEnv* env) {
jclass jclazz = env->FindClass("java/util/ArrayList");
assert(jclazz != nullptr);
return jclazz;
}
// Get the java class id of java.util.Iterator.
static jclass getIteratorClass(JNIEnv* env) {
jclass jclazz = env->FindClass("java/util/Iterator");
assert(jclazz != nullptr);
return jclazz;
}
// Get the java method id of java.util.List.iterator().
static jmethodID getIteratorMethod(JNIEnv* env) {
static jmethodID mid = env->GetMethodID(
getListClass(env), "iterator", "()Ljava/util/Iterator;");
assert(mid != nullptr);
return mid;
}
// Get the java method id of java.util.Iterator.hasNext().
static jmethodID getHasNextMethod(JNIEnv* env) {
static jmethodID mid = env->GetMethodID(
getIteratorClass(env), "hasNext", "()Z");
assert(mid != nullptr);
return mid;
}
// Get the java method id of java.util.Iterator.next().
static jmethodID getNextMethod(JNIEnv* env) {
static jmethodID mid = env->GetMethodID(
getIteratorClass(env), "next", "()Ljava/lang/Object;");
assert(mid != nullptr);
return mid;
}
// Get the java method id of arrayList constructor.
static jmethodID getArrayListConstructorMethodId(JNIEnv* env, jclass jclazz) {
static jmethodID mid = env->GetMethodID(
jclazz, "<init>", "(I)V");
assert(mid != nullptr);
return mid;
}
// Get the java method id of java.util.List.add().
static jmethodID getListAddMethodId(JNIEnv* env) {
static jmethodID mid = env->GetMethodID(
getListClass(env), "add", "(Ljava/lang/Object;)Z");
assert(mid != nullptr);
return mid;
}
};
class ByteJni {
public:
// Get the java class id of java.lang.Byte.
static jclass getByteClass(JNIEnv* env) {
jclass jclazz = env->FindClass("java/lang/Byte");
assert(jclazz != nullptr);
return jclazz;
}
// Get the java method id of java.lang.Byte.byteValue.
static jmethodID getByteValueMethod(JNIEnv* env) {
static jmethodID mid = env->GetMethodID(
getByteClass(env), "byteValue", "()B");
assert(mid != nullptr);
return mid;
}
};
// ==================== Java ArrayList<String> ==> C++ vector<string> ====================
static jclass java_util_ArrayList;
static jmethodID java_util_ArrayList_;
jmethodID java_util_ArrayList_size;
jmethodID java_util_ArrayList_get;
jmethodID java_util_ArrayList_add;
static thread_local JNIEnv* env;
void init() {
java_util_ArrayList = static_cast<jclass>(env->NewGlobalRef(env->FindClass("java/util/ArrayList")));
java_util_ArrayList_ = env->GetMethodID(java_util_ArrayList, "<init>", "(I)V");
java_util_ArrayList_size = env->GetMethodID (java_util_ArrayList, "size", "()I");
java_util_ArrayList_get = env->GetMethodID(java_util_ArrayList, "get", "(I)Ljava/lang/Object;");
java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)Z");
}
std::vector<std::string> java2cpp(jobject arrayList) {
jint len = env->CallIntMethod(arrayList, java_util_ArrayList_size);
std::vector<std::string> result;
result.reserve(len);
for (jint i=0; i<len; i++) {
jstring element = static_cast<jstring>(env->CallObjectMethod(arrayList, java_util_ArrayList_get, i));
const char* pchars = env->GetStringUTFChars(element, nullptr);
result.emplace_back(pchars);
env->ReleaseStringUTFChars(element, pchars);
env->DeleteLocalRef(element);
}
}
// ==================== C++ vector<string> ==> Java ArrayList<String> ====================
jobject cpp2java(std::vector<std::string> vector) {
jobject result = env->NewObject(java_util_ArrayList, java_util_ArrayList_, vector.size());
for (std::string s: vector) {
jstring element = env->NewStringUTF(s.c_str());
env->CallBooleanMethod(result, java_util_ArrayList_add, element);
env->DeleteLocalRef(element);
}
return result;
}
@IncPlusPlus
Copy link

IncPlusPlus commented Jul 29, 2020

For anyone who intends to use jobject cpp2java(std::vector<std::string> vector), the JVM will crash because java_util_ArrayList_add seems to have a typo. It should have a Z and not a V.
java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)V");
Becomes
java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)Z");

And one more thing, although it works fine after that, java.util.ArrayList#add(E) returns a boolean. You might want to change
env->CallVoidMethod(result, java_util_ArrayList_add, element);
to
env->CallBooleanMethod(result, java_util_ArrayList_add, element);.

@jachimsevero
Copy link

Hi, I used your code. the return statement of java2cpp() was omitted. Anyway, thank you very for this clean and easy to follow jni codes. :)

@qh-huang
Copy link
Author

qh-huang commented Aug 27, 2020

@yuvarajselvaraj, sorry for this late reply after 1 year..., unfortunately, I don't see any relationship between JNI and JSON object.
@IncPlusPlus, I just updated the gist accordingly, thank you so much!
@jachimsevero, thanks for notifying me. However, I can't reproduce the issue which you described; on the other hand, this gist is not actively maintained and maybe you will get some insight from the original code where I pull from before: https://github.com/facebook/rocksdb/blob/master/java/rocksjni/portal.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment