Search code examples
androidc++android-ndkjava-native-interface

java lang class exception -Unable to cast the java vector<user defined java class> return from c++ jni object callback


I am not able to cast back the user self defined class return from C++ jni callback

code snippet as follow:

//Kotlin class

data class  class_record(var id:String?,var class_name:String?,var class_type) 

// com.example.MainActivity

public native Object Cls(String id);

Vector vec_ classrecord=new Vector();

vec_classrecord=(Vector)Cls("1234");

// c++ jni code

extern "C" JNIEXPORT jobject JNICALL Java_com_example_MainActivity_Cls(JNIEnv *env, jobject instance, jstring id, ) {

        jclass java_vector_class;
         jmethodID  java_vector_method;
         jobject java_vector_object ;



       auto vec_record=// call c++ method that return vector for class record pointer   


        jstring jni_str;
        jclass javaClassRef;

      // jni for java.util.Vector
        java_vector_class = env->FindClass("java/util/Vector");
        java_vector_method_constructor = env->GetMethodID(java_vector_class, "<init>", "()V");
        java_vector_object = env->NewObject(java_vector_class, java_vector_method_constructor, "");


        for (auto record_it = vec_record.begin(); record_it < vec_record.end(); ++record_it) {

        // jni  for class_record
            jclass java_class = env->FindClass("com/example/class_record");
            javaClassRef = (jclass) env->NewGlobalRef(java_class);
            jmethodID cls_constructor = env->GetMethodID(javaClassRef, "<init>", "()V");
            jobject cls_object = env->NewObject(javaClassRef, cls_constructor, "");

            // set id

            javaMethodRef = env->GetMethodID(javaClassRef, "setId", "(Ljava/lang/String;)V");

            std::string strval = record_it.id;

            jni_str = env->NewStringUTF(strval.c_str());
            env->CallVoidMethod(cls_object, javaMethodRef, jni_str);

            // set class_name
            javaMethodRef = env->GetMethodID(javaClassRef, "setClass_name","(Ljava/lang/String;)V");

             std::string strval = record_it.class_name;
             jni_str = env->NewStringUTF(strval.c_str());

            env->CallVoidMethod(cls_object, javaMethodRef, jni_str);
            //set class_type

            javaMethodRef = env->GetMethodID(javaClassRef, "setClass_type","(Ljava/lang/String;)V");
            std::string strval = record_it.class_type;
            jni_str = env->NewStringUTF(strval.c_str());                             

            env->CallVoidMethod(cls_object, javaMethodRef, jni_str);


            jmethodID java_vector_add = env->GetMethodID(java_vector_class, "addElement","(Ljava/lang/Object;)V");
            **env->CallVoidMethod(java_vector_object, java_vector_add, javaClassRef);**


        }


        return java_vector_object;

    }

Solution

  • env->CallVoidMethod(java_vector_object, java_vector_add, cls_object);
    

    Under Kotlin environment , it it much better to express jni c++ callback in ArrayList instead of vector which grow almost double the size with snippet as follow in situation where the returned arraylist is fixed size immuatable.

     java_util_class = env->FindClass("java/util/ArrayList");
    
            jmethodID java_add= env->GetMethodID(java_util_class, "add","(Ljava/lang/Object;)Z");
            env->CallBooleanMethod(java_object, java_add, cls_object);
    

    sample tutorial