Java Native Method の作り方 (4)
Native Method から Java Method を呼び出す

1. コード

class Callback {
  static {
    System.loadLibrary("callback");
  }

  public native void nativeMethod(int depth);

  // Native Method からコールされるメソッド
  public void callback(int depth) {
    String h = "";
    if (depth < 5) {
      for (int i=0; i<depth; i++) h += "  ";
      System.out.println(h+"Java : Depth="+depth);
      // 再度 Native Method をコールする
      nativeMethod(depth+1);
      System.out.println(h+"Java : Depth="+depth); 
    } else {
      System.out.println(h+"LIMIT");
    }
  }

  public static void main(String args[]) {
    Callback c = new Callback();
    c.callback(0);
  }
}

Native Method からコールされるメソッドとして、callback() を用意した。この中でまた Native Method をコールして、深さが 5 になるまで繰り返す。

#include <jni.h>
#include "Callback.h"
#include <stdio.h>

void indent(int level) {
  int i;
  for (i=0; i<level; i++) printf("  ");
}

JNIEXPORT void JNICALL
Java_Callback_nativeMethod(JNIEnv *env, jobject obj, jint depth) {
  jclass cls = (*env)->GetObjectClass(env, obj);
  jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
  if (mid == 0) return;
  indent(depth);
  printf("C    : Depth=%d\n", depth); fflush(stdout);
  /* Java のメソッドをコール */
  (*env)->CallVoidMethod(env, obj, mid, depth);
  indent(depth);
  printf("C    : Depth=%d\n", depth); fflush(stdout);
}

まず Native Method は、GetObjectClass() により、自分のクラスの Class オブジェクトを取得する。 その Class オブジェクトを使ってメソッドを取得するには、次の GetMethodID() を使う。 この引数にメソッド名 ("callback") と引数・返値 ("(I)V") を渡すと、そのメソッドへの参照が得られる。 もしメソッドが見つからなかった場合、GetMethodID() は 0 を返す。 そして、最後に CallVoidMethod() で Java のメソッドをコールする。

2. 実行

% java Callback
Java : Depth=0
  C    : Depth=1
  Java : Depth=1
    C    : Depth=2
    Java : Depth=2
      C    : Depth=3
      Java : Depth=3
        C    : Depth=4
        Java : Depth=4
          C    : Depth=5
LIMIT
          C    : Depth=5
        Java : Depth=4
        C    : Depth=4
      Java : Depth=3
      C    : Depth=3
    Java : Depth=2
    C    : Depth=2
  Java : Depth=1
  C    : Depth=1
Java : Depth=0