开发者

How do I access return value of a Java method returning java.lang.String from C++ in JNI?

开发者 https://www.devze.com 2023-01-09 20:48 出处:网络
I am tr开发者_如何学Cying to pass back a string from a Java method called from C++. I am not able to find out what JNI function should I call to access the method and be returned a jstring value.

I am tr开发者_如何学Cying to pass back a string from a Java method called from C++. I am not able to find out what JNI function should I call to access the method and be returned a jstring value.

My code follows:

C++ part

main() {
    jclass cls;
    jmethodID mid;
    jstring rv;

/** ... omitted code ... */

    cls = env->FindClass("ClassifierWrapper");
    mid = env->GetMethodID(cls, "getString","()Ljava/lang/String");

    rv = env->CallStatic<TYPE>Method(cls, mid, 0);
    const char *strReturn = env->GetStringUTFChars(env, rv, 0);

    env->ReleaseStringUTFChars(rv, strReturn);
}

Java Code

public class ClassifierWrapper {
    public String getString() { return "TEST";}
}

The Method Signature (from "javap -s Class")

public java.lang.String getString();
  Signature: ()Ljava/lang/String;


You should have

cls = env->FindClass("ClassifierWrapper"); 

Then you need to invoke the constructor to get a new object:

jmethodID classifierConstructor = env->GetMethodID(cls,"<init>", "()V"); 
if (classifierConstructor == NULL) {
  return NULL; /* exception thrown */
}

jobject classifierObj = env->NewObject( cls, classifierConstructor);

You are getting static method (even though the method name is wrong). But you need to get the instance method since getString() is not static.

jmethodID getStringMethod = env->GetMethodID(cls, "getString", "()Ljava/lang/String;"); 

Now invoke the method:

rv = env->CallObjectMethod(classifierObj, getStringMethod, 0); 
const char *strReturn = env->GetStringUTFChars(env, rv, 0);


The complete working solution is as below:

Java Side

public class ClassifierWrapper {
public ClassifierWrapper(){}
public String getString() { return "TEST";}
}

Native Side

jclass cls;
jmethodID mid;
jstring rv;


cls = jniEnv->FindClass("ClassifierWrapper"); //plase also consider your package name as package\name\classname

jmethodID classifierConstructor = jniEnv->GetMethodID(cls,"<init>", "()V");
if (classifierConstructor == NULL) {
    return NULL; /* exception thrown */
}
jobject classifierObj = jniEnv->NewObject( cls, classifierConstructor);

jmethodID getStringMethod = jniEnv->GetMethodID(cls, "getString", "()Ljava/lang/String;");

rv = (jstring)(jniEnv->CallObjectMethod(classifierObj, getStringMethod));
const char *strReturn = jniEnv->GetStringUTFChars( rv, 0);


jniEnv->ReleaseStringUTFChars(rv, strReturn);


The signature ()Ljava/lang/String is wrong, due that a class name into JVM must terminate with ;, then in this case signature must be ()Ljava/lang/String;


The first problem is that ClassifierWrapper.getString() is not static. You will need to make it static or instantiate ClassifierWrapper.

The second problem is that you are using GetMethodId instead of GetStaticMethodId.

To invoke a method that returns an Object (such as a String) you would call CallStaticObjectMethod(). That will return a jobject local reference to the String that the method returned. You can safely cast the jobject to a jstring (see http://java.sun.com/docs/books/jni/html/types.html) and use GetStringUTFChars to retrieve the characters and GetStringUTFLength to get the number of characters.

JNI is very tricky. You need to check the error code for everything (use ExceptionCheck() when there is no error code). If you don't check for errors it will fail silently in most cases and usually not at the point where the actual bug is.

You also need to understand the difference between local and global references (and what methods generate new references) in order to not leak memory and run into the reference limit. For instance, FindClass returns a local reference to a class object, but GetMethodId returns a MethodID.

Good luck

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号