前言

在进行 JNI 开发的时候,经常会碰到需要传递 Map 的需求。

它们实现起来不难,但是写起来还是比较麻烦的,每次要写的时候都要老半天。

所以这里给一个参考,希望在用到的时候能帮你进行快速开发。

HashMap -> unordered_map

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
std::unique_ptr<std::unordered_map<std::string, std::string>>
hashMap2unordered_map(JNIEnv *env, jobject data) {
    std::unique_ptr<std::unordered_map<std::string, std::string>> map = std::make_unique<std::unordered_map<std::string, std::string>>();
    if (!env->IsSameObject(data, nullptr)) {
        jclass mapClass = env->FindClass("java/util/Map");
        jmethodID entrySetMethod = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
        jobject entries = env->CallObjectMethod(data, entrySetMethod);

        jclass setClass = env->FindClass("java/util/Set");
        jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");

        jclass iterClass = env->FindClass("java/util/Iterator");
        jmethodID hasNextMethod = env->GetMethodID(iterClass, "hasNext", "()Z");

        jmethodID nextMethod = env->GetMethodID(iterClass, "next", "()Ljava/lang/Object;");;

        jclass entryClass = env->FindClass("java/util/Map$Entry");
        jmethodID getKeyMethod = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");

        jmethodID getValueMethod = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");

        jobject iterator = env->CallObjectMethod(entries, iteratorMethod);
        while (env->CallBooleanMethod(iterator, hasNextMethod)) {
            jobject entry = env->CallObjectMethod(iterator, nextMethod);
            jstring jKey = static_cast<jstring>(env->CallObjectMethod(entry,
                                                                      getKeyMethod));
            std::string key;
            if (!env->IsSameObject(jKey, nullptr)) {
                const char *keyStr = env->GetStringUTFChars(jKey, nullptr);
                key.append(keyStr);
                env->ReleaseStringUTFChars(jKey, keyStr);
            }

            jstring jValue = static_cast<jstring>(env->CallObjectMethod(entry,
                                                                        getValueMethod));
            std::string value;
            if (!env->IsSameObject(jValue, nullptr)) {
                const char *valueStr = env->GetStringUTFChars(jValue, nullptr);
                value.append(valueStr);
                env->ReleaseStringUTFChars(jValue, valueStr);
            }
            map->emplace(std::move(key), std::move(value));

            env->DeleteLocalRef(jValue);
            env->DeleteLocalRef(jKey);
            env->DeleteLocalRef(entry);
        }

        env->DeleteLocalRef(iterator);

        env->DeleteLocalRef(entryClass);
        env->DeleteLocalRef(iterClass);
        env->DeleteLocalRef(setClass);
        env->DeleteLocalRef(mapClass);
    }
    return map;
}

unordered_map -> HashMap

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
jobject unordered_map2HashMap(JNIEnv *env,
                              std::unique_ptr<std::unordered_map<std::string, std::string>> params) {
    jobject map = nullptr;
    if (params) {
        jclass mapClass = env->FindClass("java/util/HashMap");
        jmethodID initMethod = env->GetMethodID(mapClass, "<init>", "()V");
        jmethodID putMethod = env->GetMethodID(mapClass, "put",
                                               "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
        map = env->NewObject(mapClass, initMethod);
        for (auto &item: *params) {
            jstring key = env->NewStringUTF(item.first.c_str());
            jstring value = env->NewStringUTF(item.second.c_str());
            env->CallObjectMethod(map, putMethod, key, value);
            env->DeleteLocalRef(value);
            env->DeleteLocalRef(key);
        }
        env->DeleteLocalRef(mapClass);
    }
    return map;
}