Richard Żak
Richard Żak

Reputation: 813

JNI jstring from class variable?

I have in my Java class a string variable:

public class myclass {
    protected final String file;
    myclass(String f) {
        file = f;
    }

    public native void processFiles();
    public static void main(String[] args) {
        myclass mc = new myclass(args[0]);
        mc.processFiles();
    }
}

In C++, I have:

JNIEXPORT void JNICALL Java_myclass_processFiles(JNIEnv *env, jobject obj) {
    jclass baseClass = env->GetObjectClass(obj);
    jfieldID fid = env->GetFieldID(baseClass, "file", "Ljava/lang/String;");
    jchar filename = env->GetCharField(baseClass, fid);
    jstring fileFieldString = env->NewString(&filename, sizeof(filename));
    const char *nativeFileString = env->GetStringUTFChars(fileFieldString, NULL);
    printf("JNI: File path: %s\n", nativeFileString);
    env->ReleaseStringUTFChars(fileFieldString, nativeFileString);
}

My output is:

JNI: File path: ??2

What am I doing wrong that isn't converting the Java string to the char* string properly? I am providing the path ~/Desktop/myfile as the sole argument, so there is a value in args[0]. My thought was that sizeof(filename) wasn't right, but there's no other option from what I can tell.

I did try this: JNI. How to get jstring from jobject and convert it to char* but when I typecast the result from GetObjectField() to jstring, I get an error:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00000001043111e8, pid=6191, tid=3591
#
# JRE version: Java(TM) SE Runtime Environment (8.0_45-b14) (build 1.8.0_45-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.45-b02 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.dylib+0x3111e8]  jni_GetStringUTFChars+0x66
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again

Also, this is just JNI and Java 8 on OSX, nothing related to Android.

Thank you.

Update: I was able to get a friend to look at it, and got it working with:

jfieldID fid = env->GetFieldID(baseClass, "file", "Ljava/lang/String;");
jstring jstr = (jstring) env->GetObjectField(thiz, fid);
const char *nativeFileString = env->GetStringUTFChars(jstr, NULL);
printf("JNI: File path: %s\n", nativeFileString);

Upvotes: 0

Views: 1837

Answers (1)

xp500
xp500

Reputation: 1426

You are doing jchar filename = env->GetCharField(baseClass, fid);

But fid is a field of type Ljava/lang/String;, not a char. So you should get that String using env->GetObjectField() and then follow what that link says.

You can also debug this better by adding env->ExceptionDescribe() after every line to see if an Exception is being thrown after your calls to env (that would be just to debug, in real production code you should be checking for exceptions after every env call and do something if something goes wrong).

By the way, maybe your code is just an example, but if that's your real code, it would be a lot easier to declare the native method as static and just pass the string as a parameter.

Upvotes: 3

Related Questions