Java 5.0から導入されたJavaのenumですが、JNIを経由したnativeメソッド内ではどのように扱えばよいのでしょうか?これについては、JNI仕様にも明記されていないようです。必要があったので、ちょっと調べてみました。
まず、次のようなテストコードを書いて、
package test;
public class ClassWithEnum {
enum Result {
OK,
NG
}
public native void method(Result result);
}
javah -jni でヘッダを出力してみます。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_ClassWithEnum */
#ifndef _Included_test_ClassWithEnum
#define _Included_test_ClassWithEnum
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test_ClassWithEnum
* Method: method
* Signature: (Ltest/ClassWithEnum/Result;)V
*/
JNIEXPORT void JNICALL Java_test_ClassWithEnum_method
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif
enumのResultは、nativeメソッドにjobject型で渡されることがわかります。では、このjobjectからenum値を取り出すには、どうすればよいのでしょうか?
実は、Javaのenumは、コンパイル時に暗黙でjava.lang.Enum型を継承したクラスに変換されています。確認のため、javapでResultクラスをデコンパイルすると、次のような結果が得られます。
Compiled from "ClassWithEnum.java"
final class test.ClassWithEnum$Result extends java.lang.Enum{
public static final test.ClassWithEnum$Result OK;
public static final test.ClassWithEnum$Result NG;
static {};
public static test.ClassWithEnum$Result[] values();
public static test.ClassWithEnum$Result valueOf(java.lang.String);
}
ここまで判れば、後は普通のjobjectを扱うのと同様です。引数のResultがOKかどうかを調べる処理は、
void JNICALL Java_test_ClassWithEnum_method(JNIEnv *env, jobject obj, jobject result) {
jclass result_class = env->FindClass("Ltest/ClassWithEnum$Result;");
jfieldID result_ok_field = env->GetStaticFieldID(result_class, "OK", "Ltest/ClassWithEnum$Result;");
jobject result_ok_object = env->GetStaticObjectField(result_class, result_ok_field);
jmethodID equals_method = env->GetMethodID(result_class, "equals", "(Ljava/lang/Object;)Z");
if (env->CallBooleanMethod(result_ok_object, equals_method, result) == JNI_TRUE) {
// Result OK
}
}
と書くことができます(エラー処理省略)。同一のclass staticフィールドを参照していても、jobject同士の”==”比較ではTRUEにならないようなので、equalsメソッドを使っています。
(2009.2.14 追記)
これらのjobjectは、”同一のJava objectへの参照”を持つ別のインスタンスなので、単純な”==”比較はできません。こういった場合は、わざわざequalsメソッドを取得しなくても、JNI関数のIsSameObject()が使えます。
戻り値としてResultの値を返すなら、GetStaticObjectFieldで取得したjobjectを返せばOKです。enum値をStringに変換するname()、Stringをenum値に変換するvalueOf()などのメソッドも使えます。
JNIとしては、enumだからといって特別な処理を行っているわけではなく、通常のjobject型の扱いと同じなので、JNIの仕様には明記していないということなのでしょう。

enumの扱い、一生懸命JNIの仕様探していました。助かりました・・・ありがとうございます。
コメントありがとうございます。私もいろいろ探したのですが、見つからなかったので調べてみました。お役に立ててなによりです。