Sunday, April 25, 2021

How to I call String.getBytes() in JNI

I am trying to call String.getBytes() method to get byte array in JNI from a string object. The JNI has methods CallByteMethod, CallByteMethodV and CallByteMethodA which returns jbyte but it has no methods to return a java byte array.

How to I call String.getBytes() in JNI

I have tried calling CallByteMethod method, but I get an error

The other code I tried was using a cast of jbytearray like this

jbyteArray keyBytes = (jbyteArray)(*env)->CallByteMethod(env, stringValue, getBytesMId);

since the IDE showed a warning

but then I get a different error that says

JNI DETECTED ERROR IN APPLICATION: the return type of CallByteMethod does not match byte[] java.lang.String.getBytes()

Below is my code:

JNIEXPORT jstring JNICALL

Java_net_jni_test_MainActivity_callTest(JNIEnv *env, jobject instance) {

    jstring stringValue = "test";

    jclass stringClass = (*env)->FindClass(env, "java/lang/String");

    jmethodID getBytesMId = (*env)->GetMethodID(env, stringClass, "getBytes", "()[B");

    jbyteArray keyBytes = (*env)->CallByteMethod(env, stringValue, getBytesMId);

    return (*env)->NewStringUTF(env, "1111");

}

Just spot some errors from your code:

Below line is wrong:

jstring stringValue = "test";

And it should be like below:

jstring stringValue = (*env)->NewStringUTF(env, "test");

Use CallObjectMethod to get the jbyteArray, remember to cast the return type to jbyteArray. See below:

jbyteArray keyBytes = (jbyteArray)(*env)->CallObjectMethod(env, stringValue, getBytesMId);

Below is a screenshot showing the expected result.

For full source:

JNIEXPORT jstring JNICALL

Java_net_jni_test_MainActivity_callTest(JNIEnv *env, jobject instance) {

    jstring stringValue = (*env)->NewStringUTF(env, "test");

    jclass stringClass = (*env)->FindClass(env, "java/lang/String");

    jmethodID getBytesMId = (*env)->GetMethodID(env, stringClass, "getBytes", "()[B");

    jbyteArray keyBytes = (jbyteArray)(*env)->CallObjectMethod(env, stringValue, getBytesMId);

    // determine the needed length and allocate a buffer for it

    jsize num_bytes = (*env)->GetArrayLength(env, keyBytes);

    // obtain the array elements

    jbyte* elements = (*env)->GetByteArrayElements(env, keyBytes, NULL);

    if (!elements) {

        // handle JNI error ...

    }

    for(int i = 0; i < num_bytes; i++) {

        char ch = elements[i];

        ALOGI("arrayLength: %c", ch);

    }

    // Do not forget to release the element array provided by JNI:

    (*env)->ReleaseByteArrayElements(env, keyBytes, elements, JNI_ABORT);

}

Please note the difference of C++ JNI and C JNI. E.g. C style JNI have below method convention:

jmethodID getBytesMId = (*env)->GetMethodID(env, stringClass, "getBytes", "()[B");

But C++ is like below:

jmethodID getBytesMId = env->GetMethodID(stringClass, "getBytes", "()[B");

No comments:

Post a Comment