Need a JNI expert: std::map -> Java HashMap

I am trying to send a std::map<> from C++ to my Java application through JNI. I have gotten basics to work through JNI such as strings and ints, but I cannot get the map to go through. I have done research and found it needs to be converted to a jobject HashMap. There is no complete answer I found anywhere so I had to piece certain parts of different answers and can’t get it to work.

On the C++ side:

void AppAnalytics::sendCustomAction(std::string name, std::map<std::string, std::string> strings, std::map<std::string, int> ints) {

cocos2d::JniMethodInfo methodInfo;

if (! getJNIStaticMethodInfo(methodInfo, "sendCustomAction", "(Ljava/lang/String;java/util/HashMap;java/util/HashMap;)V")) {
    return;
}

jclass clazz = methodInfo.env->FindClass("java/util/HashMap");
jmethodID init = methodInfo.env->GetMethodID(clazz, "<init>", "()V");
jobject stringMap = methodInfo.env->NewObject(clazz, init);

jmethodID putMethod = methodInfo.env->GetMethodID(
                                       clazz,
                                       "put",
                                                  "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"
                                       );

map<std::string, std::string>::iterator itStr;
for ( itStr = strings.begin(); itStr != strings.end(); itStr++ ) {
    const char * firstStr = itStr->first.c_str();
    const char * secondStr = itStr->second.c_str();

    jstring key = methodInfo.env->NewStringUTF( firstStr );
    jstring value = methodInfo.env->NewStringUTF( secondStr );

    methodInfo.env->CallObjectMethod(
                                     stringMap,
                                     putMethod,
                                     key,
                                     value
                                     );
}

jobject intMap = methodInfo.env->NewObject(clazz, init);


map<std::string, int>::iterator itInt;
for ( itInt = ints.begin(); itInt != ints.end(); itInt++ ) {
    const char * firstStr = itInt->first.c_str();

    jstring key = methodInfo.env->NewStringUTF( firstStr );
    int value = itInt->second;

    methodInfo.env->CallVoidMethod(
                                     intMap,
                                     putMethod,
                                     key,
                                     value
                                     );
}

jstring stringArg = methodInfo.env->NewStringUTF(name.c_str());
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg, stringMap, intMap);
methodInfo.env->DeleteLocalRef(stringArg);
methodInfo.env->DeleteLocalRef(stringMap);
methodInfo.env->DeleteLocalRef(intMap);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

This is on the receiving side on the Java application:

public class AnalyticsHelper {

public static void sendCustomAction(String name, HashMap<String, String> strings, HashMap<String, Integer> ints) {
    CustomEvent event = new CustomEvent(name);

    for (String key : strings.keySet()) {
        event.putCustomAttribute(key, strings.get(key));
    }
    for (String key : ints.keySet()) {
        event.putCustomAttribute(key, ints.get(key));
    }

    Answers.getInstance().logCustom(event);
}

}

I keep getting this error on the Java side when I trigger the action from within the app:

E/JniHelper: Failed to find static method id of sendCustomAction

Any help would be greatly appreciated. I have tried different combinations of what I have and can never seem to get it though.

Thanks!

Stackoverflow was a help!
Just incase anyone wants the answer:

I forgot the ‘L’ in object notation in the method signature. JNI is not very friendly with compile/runtime errors.

1 Like