4
votes

I have this class in Java:

public class CameraActivity extends Activity {

  ...      

  public class RecognitionResult {
    public String text;
    public int x;
    public int y;
    public int width;
    public int height;

    public RecognitionResult(String text, int x, int y, int width, int height) {
      this.text = text;
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    }
  }
}

And this is my JNI code:

extern "C"
jobject Java_com_example_parkingcontrolsystem_CameraActivity_recognizeNumberPlate(JNIEnv *env,
                                                                                  jobject object,
                                                                                  jstring filename)
{
  jclass cls = env->FindClass("com/example/parkingcontrolsystem/CameraActivity$RecognitionResult");
  std::cout << "Class: " << cls << std::endl;

  jmethodID constructor = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;IIII)V");
  std::cout << "Method: " << constructor << std::endl;

  recognition_result = env->NewObject(cls, constructor, "Hello from JNI", 0, 0, 50, 100);
  std::cout << "Object: " << recognition_result << std::endl;

  return recognition_result;
}

FindClass returns not a NULL, OK. But GetMethodID always returns zero. I tried to make the default constructor without args, and than use the "()V" signature, but GetMethodID returns NULL.

What is wrong?

1
stackoverflow.com/questions/70324/… "(Lcom/example/parkingcontrolsystem/CameraActivity;Ljava/lang/String;IIII)V" - Selvin
Just 2 more cents: Next problem is that you can not call this constructor without CameraActivity instance (but i'm not sure if it is possible to do in JNI)... so it is better for you to make it static inner class or not inner at all - Selvin
Thanks, man! Method was found! OK, I make this class as a static inner class. - herolover
OK, thank you very much! :) - herolover
2Selvin: make it an answer, please, so that the OP can accept and future generations can edify themselves. - Seva Alekseyev

1 Answers

3
votes

If instantiating a inner class using JNI the parent must be passed also in the signature used with GetMethodIdin order to receive a valid jmethodID.

Assuming Bis a inner class of A and has a constructor like: public B(int someint) the following code would work(jobj is pointing to a instance of A):

jclass jclazz = env->FindClass("org/somepackage/A$B");
assert(jclazz != nullptr);
jmethodID mid = env->GetMethodID(jclazz, "<init>", "(Lorg/somepackage/A;I)V");
assert(mid != nullptr);
env->NewObject(jclazz, mid, jobj, 1);

A solution to the ops question is:

 jclass cls = env->FindClass("com/example/parkingcontrolsystem/CameraActivity$RecognitionResult");
 std::cout << "Class: " << cls << std::endl;
 jmethodID constructor = env->GetMethodID(cls, "<init>","Lcom/example/parkingcontrolsystem/CameraActivity;Ljava/lang/String;IIII)V");
 std::cout << "Method: " << constructor << std::endl;
 recognition_result = env->NewObject(cls, constructor, object, "Hello from JNI", 0, 0, 50, 100);
 std::cout << "Object: " << recognition_result << std::endl;

Note: Creds to Selven who posted also the same answer in the comments but didn`t post an answer.