Search code examples
javaandroidc++java-native-interface

How to set the value of a Double/Integer type of a java class by JNI


Earlier, I ask a question as:

How can I set the value of “Double” type variable of my Class by JNI?

But, I didn't get the right answer what I want. Assume I had a java class like:

class Data
{
    public Integer value;
}

Native:

public static native int testGet(Data tdobj);

c codes:

JNIEXPORT jint JNICALL
test_jni_Native_testSet(JNIEnv *env, jclass type, jobject tdobj)
{
    jclass tdobjClass = env->FindClass("xxxx/Data");
    jfieldID valueID = env->GetFieldID(tdobjClass, "value", "Ljava/lang/Integer;");
    env->SetIntField(tdobj, jValueID, 123);
    return 0;
}

And when I called Native.testGet, the program broke down, and show erro messages as follows:

E/dalvikvm: JNI ERROR (app bug): accessed stale weak global reference 0x7b (index 30 in a table of size 6)
E/dalvikvm: VM aborting
Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 26758 

I really don't know

How to deal with Double/Integer types in a class, which seems like the same as String ones, but it differs from String type. It seems like that such types can be handled by jobject, but result makes me confused.

Thanks.

I don't want to use a primitive type like double/int to reach my goal, and I don't want to use functions either. Or you may just tell me that, the way I wished is impossible to reach my goal. Thanks a lot~~


Solution

  • First thing, when you get value field from Data instance, it is not initialized, as your java code shows, so would need to create an instance.

    Second, you can't change integer value, you have to instantiate it with the value you want. So, create a new Integer, and then change value field from Data instance. Something like this:

    JNIEXPORT jint JNICALL test_jni_Native_testSet(JNIEnv *env, jclass type, jobject tdobj)
    {
        //Create Integer class, get constructor and create Integer object
        jclass intClass = env->FindClass(env, "java/lang/Integer");
        jmethodID initInt = env->GetMethodID(env, intClass, "<init>", "(I)V");
        if (NULL == initInt) return -1;
            jobject newIntObj = env->NewObject(env, intClass, initInt, 123);
    
        //Now set your integer into value atttribute. For this, I would
        //recommend you to have a java setter and call it in the same way 
        //as shown above
    
        //clean reference
        env->DeleteLocalRef(env, newIntObj); 
        return 0;
    }