JNI: create a HashMap

How to create a HashMap object in JNI?

+9
hashmap jni
source share
5 answers

Here is the code you will need to change to work

jclass mapClass = (*env)->FindClass(env, "java/util/HashMap"); if(mapClass == NULL) { return NULL; } jsize map_len = 1; jmethodID init = (*env)->GetMethodID(env, mapClass, "<init>", "(I)V"); jobject hashMap = (*env)->NewObject(env, mapClass, init, map_len); jmethodID put = (*env)->GetMethodID(env, mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); while( ... ) { jint key = ...; size_t sz = t->count; jbyteArray dd = (*env)->NewByteArray(env, sz); for(i = 0; i < sz; i++) { (*env)->SetByteArrayRegion(env, dd, i, 1, *data++); } (*env)->CallObjectMethod(env, hashMap, put, key, dd); (*env)->DeleteLocalRef(env, key); (*env)->DeleteLocalRef(env, dd); } (*env)->DeleteLocalRef(env, hashMap); (*env)->DeleteLocalRef(env, mapClass); 
+16
source share

For me, I found that the signature of the put method must be different from that specified in the above example. i.e.

 jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 
+3
source share

See here :

Sample code to invoke the String constructor:

 jstring MyNewString(JNIEnv *env, jchar *chars, jint len) { jclass stringClass; jmethodID cid; jcharArray elemArr; jstring result; stringClass = (*env)->FindClass(env, "java/lang/String"); if (stringClass == NULL) { return NULL; /* exception thrown */ } /* Get the method ID for the String(char[]) constructor */ cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V"); if (cid == NULL) { return NULL; /* exception thrown */ } /* Create a char[] that holds the string characters */ elemArr = (*env)->NewCharArray(env, len); if (elemArr == NULL) { return NULL; /* exception thrown */ } (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars); /* Construct a java.lang.String object */ result = (*env)->NewObject(env, stringClass, cid, elemArr); /* Free local references */ (*env)->DeleteLocalRef(env, elemArr); (*env)->DeleteLocalRef(env, stringClass); return result; } 
+2
source share

You can also consider alternatives to using JNI directly - for example, tools that can generate JNI code for you. For example, JANET (disclaimer: I wrote it) allows you to embed Java code in your own methods, so creating and using a hash map is then simple:

 ... (C++ code) `Map map = new HashMap();` // embedded Java ... (C++ code) ... const char* foo = "foo"; `map.put(#$(foo), 50);` // ["foo" -> 50] 

reverse type operators are translated by JANET code into JNI, so you never have to worry about signatures, link handling, exception handling, etc., but you still get JNI performance.

+2
source share

Below is my contribution to this question, I used ideas from other answers and other places. Below are two functions that convert std::map<std::string, std::string> to HashMap and vice versa:

 jobject StlStringStringMapToJavaHashMap(JNIEnv *env, const std::map<std::string, std::string>& map); void JavaHashMapToStlStringStringMap(JNIEnv *env, jobject hashMap, std::map<std::string, std::string>& mapOut); 

Test function:

 void TestConversions(JNIEnv *env); 

gives examples of how to use it - by the way. I tested this test on an Android device and it works.

 jobject StlStringStringMapToJavaHashMap(JNIEnv *env, const std::map<std::string, std::string>& map) { jclass mapClass = env->FindClass("java/util/HashMap"); if(mapClass == NULL) return NULL; jmethodID init = env->GetMethodID(mapClass, "<init>", "()V"); jobject hashMap = env->NewObject(mapClass, init); jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); std::map<std::string, std::string>::const_iterator citr = map.begin(); for( ; citr != map.end(); ++citr) { jstring keyJava = env->NewStringUTF(citr->first.c_str()); jstring valueJava = env->NewStringUTF(citr->second.c_str()); env->CallObjectMethod(hashMap, put, keyJava, valueJava); env->DeleteLocalRef(keyJava); env->DeleteLocalRef(valueJava); } jobject hashMapGobal = static_cast<jobject>(env->NewGlobalRef(hashMap)); env->DeleteLocalRef(hashMap); env->DeleteLocalRef(mapClass); return hashMapGobal; } // Based on android platform code from: /media/jni/android_media_MediaMetadataRetriever.cpp void JavaHashMapToStlStringStringMap(JNIEnv *env, jobject hashMap, std::map<std::string, std::string>& mapOut) { // Get the Map entry Set. jclass mapClass = env->FindClass("java/util/Map"); if (mapClass == NULL) { return; } jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); if (entrySet == NULL) { return; } jobject set = env->CallObjectMethod(hashMap, entrySet); if (set == NULL) { return; } // Obtain an iterator over the Set jclass setClass = env->FindClass("java/util/Set"); if (setClass == NULL) { return; } jmethodID iterator = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); if (iterator == NULL) { return; } jobject iter = env->CallObjectMethod(set, iterator); if (iter == NULL) { return; } // Get the Iterator method IDs jclass iteratorClass = env->FindClass("java/util/Iterator"); if (iteratorClass == NULL) { return; } jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); if (hasNext == NULL) { return; } jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); if (next == NULL) { return; } // Get the Entry class method IDs jclass entryClass = env->FindClass("java/util/Map$Entry"); if (entryClass == NULL) { return; } jmethodID getKey = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); if (getKey == NULL) { return; } jmethodID getValue = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); if (getValue == NULL) { return; } // Iterate over the entry Set while (env->CallBooleanMethod(iter, hasNext)) { jobject entry = env->CallObjectMethod(iter, next); jstring key = (jstring) env->CallObjectMethod(entry, getKey); jstring value = (jstring) env->CallObjectMethod(entry, getValue); const char* keyStr = env->GetStringUTFChars(key, NULL); if (!keyStr) { // Out of memory return; } const char* valueStr = env->GetStringUTFChars(value, NULL); if (!valueStr) { // Out of memory env->ReleaseStringUTFChars(key, keyStr); return; } mapOut.insert(std::make_pair(std::string(keyStr), std::string(valueStr))); env->DeleteLocalRef(entry); env->ReleaseStringUTFChars(key, keyStr); env->DeleteLocalRef(key); env->ReleaseStringUTFChars(value, valueStr); env->DeleteLocalRef(value); } } void TestConversions(JNIEnv *env) { // Empty test { std::map<std::string, std::string> map, mapTest; jobject hashMap = StlStringStringMapToJavaHashMap(env, map); JavaHashMapToStlStringStringMap(env, hashMap, mapTest); assert(map == mapTest); } // One element test { std::map<std::string, std::string> map, mapTest; map["one"] = "uno"; jobject hashMap = StlStringStringMapToJavaHashMap(env, map); JavaHashMapToStlStringStringMap(env, hashMap, mapTest); assert(map == mapTest); } // Two element test { std::map<std::string, std::string> map, mapTest; map["one"] = "uno"; map["two"] = "duo"; jobject hashMap = StlStringStringMapToJavaHashMap(env, map); JavaHashMapToStlStringStringMap(env, hashMap, mapTest); assert(map == mapTest); } // Huge number of elements test { std::map<std::string, std::string> map, mapTest; for (int n = 0; n < 10000; ++n) { map[std::to_string(n)] = std::to_string(n); } jobject hashMap = StlStringStringMapToJavaHashMap(env, map); JavaHashMapToStlStringStringMap(env, hashMap, mapTest); assert(map == mapTest); } } 
0
source share

All Articles