Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert char* to jstring in JNI, when char* is passed using va_arg

Is it necessary to convert char* to jbyteArray, then call java String's contructor to generate a jstring? How else can it be done? Please help.

static int testhandler(void *arg, ...)
 {
    int i;
    struct callback *cb = (struct callback *)arg;

    JNIEnv *env = cb->env;
    char *sig = cb->signature;

    jint size = (jint) strlen(sig);
    jint size1;
    va_list arguments;

    jobjectArray return_array;
    jclass obj_class;
    jbyteArray bytes;
    jstring str;

    obj_class = (*env)->FindClass(env, "java/lang/Object");
    return_array = (*env)->NewObjectArray(env, size, obj_class, NULL);

    va_start(arguments, arg);

    for (i = 0; i < size; i++) {
        jclass clazz;
        jmethodID id;
        jobject obj;
        jobject encoding;
        switch (sig[i]) {
            case 'i': {
                clazz = (*env)->FindClass(env, "java/lang/Integer");
                id = (*env)->GetMethodID(env, clazz, "<init>", "(I)V");
                obj = (*env)->NewObject(env, clazz, id, va_arg(arguments, uint32_t));
                (*env)->SetObjectArrayElement(env, return_array, i, obj);
                break;
            }
            case 'l': {
                clazz = (*env)->FindClass(env, "java/lang/Long");
                id = (*env)->GetMethodID(env, clazz, "<init>", "(J)V");
                obj = (*env)->NewObject(env, clazz, id, va_arg(arguments, uint64_t));
                (*env)->SetObjectArrayElement(env, return_array, i, obj);
                break;
            }
            case 's': {
                clazz = (*env)->FindClass(env, "java/lang/String");
                size1 = (jint) strlen(va_arg(arguments, char *));
                id = (*env)->GetMethodID(env, clazz, "<init>", "([BLjava/lang/String;)V");

                encoding = (*env)->NewStringUTF(env, va_arg(arguments, char *)); 
                bytes = (*env)->NewByteArray(env, size1); 
                (*env)->SetByteArrayRegion(env, bytes, 0, size1, (jbyte *)(va_arg(arguments, char *)));

                str = (jstring)(*env)->NewObject(env, clazz, id , bytes);
                obj = (*env)->NewObject(env, clazz, id, str);
                (*env)->SetObjectArrayElement(env, return_array, i, obj);
                break;
            }
            default: {
                printf("unknown signature char '%c'\n", sig[i]);
            }
        }

    }
    va_end(arguments);
    (*env)->CallVoidMethod(env, cb->handler, cb->id, return_array);

    return 0;
}
like image 646
user2358330 Avatar asked Jun 05 '13 11:06

user2358330


2 Answers

You could just check JNI api documentation. E.g. Here.
You will find:

jstring NewStringUTF(JNIEnv *env, const char *bytes);

So all you have to do it something like this:

char *buf = (char*)malloc(10);
strcpy(buf, "123456789"); // with the null terminator the string adds up to 10 bytes
jstring jstrBuf = (*env)->NewStringUTF(env, buf);
like image 151
mkaes Avatar answered Sep 21 '22 12:09

mkaes


It depends on the nature of your char * string. NewStringUTF copies from a 0-terminated, modified UTF-8 encoding of Unicode characters. NewString copies from a counted, UTF-16 encoding of Unicode characters. If you don't have either of those, you have to perform a conversion.

A lot of code using NewStringUTF is written with the assumption that the string is NUL-terminated ASCII. If that assumption is correct then it will work because the modified UTF-8 encoding and the ASCII encoding would produce the same byte sequence. Such code should be clearly commented to document the restriction on the string data.

The conversion method you allude to—calling Java functions (e.g. String(byte[] bytes, Charset charset)) —is a good one. One alternative (in Windows, I see you are using Visual Studio) is MultiByteToWideChar. Another alternative is iconv.

Bottom line: You have to know what character set and encoding your string uses and then convert it to a UTF-16 encoded Unicode for use as a Java String.

like image 21
Tom Blodget Avatar answered Sep 19 '22 12:09

Tom Blodget