14

I'm trying to use a JNI function to create a Java class and set some properties of that class using the DeviceId.java constructor method. I'm able to get the constructor method using the GetMethodID, but how would I create a new instance of Device.java and then set the properties (setId and setCache). The goal is to return a fully populated instance of Device.java Object to the caller. Any ideas?

JNI Function:

 JNIEXPORT jobject JNICALL Java_com_test_getID(JNIEnv *env, jclass cls) 
    {
        jmethodID cnstrctr;
        jclass c = (*env)->FindClass(env, "com/test/DeviceId");
        if (c == 0) {
            printf("Find Class Failed.\n");
         }else{
            printf("Found class.\n");
         }

        cnstrctr = (*env)->GetMethodID(env, c, "<init>", "(Ljava/lang/String;[B)V");
        if (cnstrctr == 0) {
            printf("Find method Failed.\n");
        }else {
            printf("Found method.\n");
        }

        return (*env)->NewObject(env, c, cnstrctr);
    }

Java Class:

package com.test;

public class DeviceId {
    private String id;
    private byte[] cache;

        public DeviceId(){}
    public DeviceId(String id, byte[] cache){
        this.id=id;
        this.cache=cache;
    }

    public byte[] getCache() {
        return cache;
    }

    public void setCache(byte[] cache) {
        this.cache = cache;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }   
}
2
  • What's the "[B" in "(Ljava/lang/String;[B)V"? Commented Aug 30, 2016 at 18:48
  • @WilburWhateley, it's an array of bytes Commented Oct 14, 2016 at 2:08

2 Answers 2

10

When you called GetMethodID, you provided the signature for the two-arg constructor. Thus, you just need to pass your jstring and a jbytearray when you call NewObject - for example:

return (*env)->NewObject(env, c, cnstrctr, id, cache);

You don't need to call the setId and setCache methods unless you decide to call the 0-arg constructor - and that just complicates your code since you'll have to call GetMethodID for those and call them. Simpler to continue down the route you're on.

Sign up to request clarification or add additional context in comments.

1 Comment

Should there be a NewGlobalRef since it would go out of scope when we return.
2

I wanted to return a custom Java object from JNI's cpp code back to Java. The solution is to return a jobject from cpp function and use our custom Java object in native method declaration.

public class PyError {

    public String message;

    public boolean occurred;

    public PyError(boolean occurred, String message){
        this.message = message;
        this.occurred = occurred;
    }
} 

and method declaration in Java:

native PyError nativePythonErrorOccurred();

on the cpp side:

extern "C" JNIEXPORT jobject JNICALL
Java_com_your_package_nativePythonErrorOccurred(JNIEnv *env, jobject obj) {

    jclass javaLocalClass = env->FindClass("com/your/package/PyError");

    if (javaLocalClass == NULL) {
        LOGP("Find Class Failed.\n");
    } else {
        LOGP("Found class.\n");
    }

    jclass javaGlobalClass = reinterpret_cast<jclass>(env->NewGlobalRef(javaLocalClass));

    // info: last argument is Java method signature
    jmethodID javaConstructor = env->GetMethodID(javaGlobalClass, "<init>", "(ZLjava/lang/String;)V");

    if (javaConstructor == NULL) {
        LOGP("Find method Failed.\n");
    } else {
        LOGP("Found method.\n");
    }

    jobject pyErrorObject = env->NewObject(javaGlobalClass, javaConstructor, true, env->NewStringUTF("Sample error body"));
    return pyErrorObject;
}

Determine the signature of the method using javap -s java.your.package.YourClass. Also, have a look here.

If you encounter error similar to: JNI ERROR (app bug): attempt to use stale Global 0xf2ac01ba your method signature is wrong, you're passing wrong arguments to env->NewObject() or you're not using global state of jni objects - more here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.