Search code examples
androidc++java-native-interfacestd-pairjnienv

How to access Pair<> of Java in JNI?


I have ArrayList<Pair<Pair<Float, Float>, Pair<Float, Float>>> on Java side and want to use this data in JNI.

What methods and classes to use to convert to std::pair<std::pair<float, float>, std::pair<float, float>>

I tried following

jclass pairClass = env->FindClass("android/util/Pair");

jfieldID pairGetKey = env->GetFieldID(pairClass, "first", "java/util/Objects");

pairGetKey is always null


Solution

  • The type of the field has to be given as a signature; that is, you need to use the int -> I, T[] -> [T, reference.Type -> Lreference/Type; encoding. Also, the type of the field is java.lang.Object, not java.util.Objects.

    jfieldID first = env->GetFieldID(pairClass, "first", "Ljava/lang/Object;");
    jfieldID second = env->GetFieldID(pairClass, "second", "Ljava/lang/Object;");
    

    The rest is tedious, but not hard:

    jfloat extract_float(JNIEnv *env, jobject f) {
        // Note the syntax of signatures: float floatValue() has signature "()F"
        return env->CallFloatMethod(f,
            env->GetMethodID(env->FindClass("java/lang/Float"), "floatValue", "()F"));
    }
    std::pair<jobject, jobject> extract_pair(JNIEnv *env, jobject p) {
        jclass pairClass = env->FindClass("android/util/Pair");
        jfieldID first = env->GetFieldID(pairClass, "first", "Ljava/lang/Object;");
        jfieldID second = env->GetFieldID(pairClass, "second", "Ljava/lang/Object;");
    
        return std::pair(env->GetObjectField(p, first), env->GetObjectField(p, second));
    }
    
    JNIEnv *env;
    jobject pair;
    auto [f1, f2] = extract_pair(env, pair);
    auto [f11, f12] = extract_pair(env, f1);
    auto [f21, f22] = extract_pair(env, f2);
    std::pair p(
            std::pair(extract_float(env, f11), extract_float(env, f12)),
            std::pair(extract_float(env, f21), extract_float(env, f22)));
    

    Though, I think I must ask, do you actually need to do this? Can you preprocess the nested pairs to something nicer on the Java side? Doing it on this side is ugly.