Как получить значение перечисления, передаваемого в JNI

У меня есть приложение Java и JNI (dll). Я хочу знать, как получить значение перечисления (int), которое передается в качестве параметра JNI.

Вот перечисление (Java):

public enum envelopeType
{
    NOT_SPECIFIED(-1),
    NONE(0),
    IMAGE(1),
    BITMAP(2);

    private int value;

    private envelopeType(int value)
    {
        this.value = value;
    }   
}

Вот код JNI (С++):

JNIEXPORT jint JNICALL Java_Loader_Convert
  (JNIEnv *env, jobject obj, jobject EnvelopeType)

поскольку перечисление передается как объект, как я могу получить его значение?


person BebzSusuma    schedule 06.08.2013    source источник


Ответы (3)


Я не смог использовать решение, предоставленное @tbodt, но оно было достаточно близко, чтобы я смог найти решение.

Глядя на документацию перечисления Java, можно увидеть метод ordinal, который вернет значение перечисления как тип int.

Код, который я использовал, был почти идентичен приведенному в решении @tbodts, однако строки, переданные в функцию GetMethodID, отличаются. Мне не нужно создавать метод getValue, а сигнатура метода ()I, а не I().

JNIEXPORT jint JNICALL Java_Loader_Convert(JNIEnv *env, jobject obj, jobject EnvelopeType) {
    jmethodID envelopeGetValueMethod = (*env)->GetMethodID(env, (*env)->FindClass(env, "package/of/envelopeType"), "ordinal", "()I");
    jint value = (*env)->CallIntMethod(env, EnvelopeType, envelopeGetValueMethod);
    switch (value) {
        case -1:
        // not specified
        break;
        case 0:
        // none
        break;
        ...
    }
    // rest of native method
}
person gnash117    schedule 26.01.2015
comment
Это реальный ответ, поскольку он не требует изменения перечисления. - person Leandros; 23.09.2015
comment
Спасибо, хотя я, вероятно, просто передам значение ordinal() функции JNI, которая принимает целое число. Мне кажется чище. - person Emile Vrijdags; 03.04.2017

На самом деле, вместо определения метода getValue() вы можете вызвать Enum.ordinal().

Более простое решение состоит в том, чтобы немного изменить код C и использовать Enum.ordinal() напрямую при вызове функции JNI, т. е. передать объект jint вместо объекта Enum:

JNIEXPORT jint JNICALL Java_Loader_convert
  (JNIEnv *env, jobject obj, jint EnvelopeType)

И в Java у вас есть своего рода

loader.convert(myEnvelopeType.ordinal());

http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#ordinal%28%29

person lnstadrum    schedule 07.08.2015

Вы должны предоставить метод для возврата значения value, затем вызвать его из собственного кода и использовать оператор switch. Вот метод в перечислении:

public int getValue() {
    return value;
}

И ваш родной метод:

JNIEXPORT jint JNICALL Java_Loader_Convert(JNIEnv *env, jobject obj, jobject EnvelopeType) {
    jmethodID envelopeGetValueMethod = (*env)->GetMethodID(env, (*env)->FindClass(env, "package/of/envelopeType"), "getValue", "()I");
    jint value = (*env)->CallIntMethod(env, EnvelopeType, envelopeGetValueMethod);
    switch (value) {
        case -1:
        // not specified
        break;
        case 0:
        // none
        break;
        ...
    }
    // rest of native method
}
person tbodt    schedule 06.08.2013
comment
Я сделаю это через минуту, когда узнаю о JNI. (Шучу, я немного в этом разбираюсь.) - person tbodt; 06.08.2013
comment
На самом деле нет необходимости добавлять метод. Собственная функция также может использовать GetFieldID() для значения поля private и использовать GetIntField() для анализа значения с той же логикой переключения. - person Alex Cohn; 06.08.2013
comment
У меня не было собственных методов, которые могли бы получить доступ к закрытым полям без чего-либо вроде setAccessible(true). - person tbodt; 06.08.2013
comment
Спасибо за ответ, я попробовал код, который вы указали выше, но jvm дает сбой при вызове CallIntMethod. Вот код: jclass конвертТипКласс = env->FindClass(JacsLoader); jmethodID EnvelopeGetValueMethod = env->GetMethodID(envelopeTypeClass, getValue, I()); jint EnvelopeTypeValue = env->CallIntMethod(EnvelopeType, inputEnvelopeGetValueMethod); - person BebzSusuma; 06.08.2013
comment
@BebzSusuma Любое исключение? Это могло произойти из-за неправильного написания имени метода или подписи. - person tbodt; 06.08.2013
comment
Как я могу поймать исключение в JNI? - person BebzSusuma; 06.08.2013
comment
ну во-первых какое исключение - person tbodt; 06.08.2013
comment
jvm показывает только это: Средой выполнения Java обнаружена фатальная ошибка: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x5ac59d7b, pid=2908, tid=6868 # # Версия JRE: 7.0-b147 # Java VM: Java HotSpot( TM) Клиентская виртуальная машина (смешанный режим 21.0-b17, совместное использование windows-x86) # Проблемный фрейм: # V [jvm.dll+0xa9d7b] - person BebzSusuma; 06.08.2013
comment
Хорошо, тогда я понятия не имею, что происходит, тем более, что я практически ничего не знаю о нативных методах. - person tbodt; 06.08.2013
comment
Вы должны указать полный путь к классу для функции FindClass. К счастью, вам это вообще не нужно: вместо этого используйте GetObjectClass(). - person Alex Cohn; 06.08.2013
comment
Я пытаюсь добавить некоторую обработку исключений в свой JNI. примерно так: jclass inputEnvelopeClass = env->GetObjectClass(inputEnvelope); if (env-›ExceptionCheck()) { MessageBox(NULL,исключение здесь,,0); } Отображается окно сообщения, означающее, что действительно существует исключение. Что не так с GetObjectClass()? - person BebzSusuma; 07.08.2013
comment
У вас синтаксическая опечатка. Изменить : I() на -› ()I. первый аргумент представляет то, что функция получает, а второй — что она возвращает. ()-› я не принимаю аргументов. I -> вернуться в - person Maor Hadad; 24.11.2015