Не могу использовать внешний класс Java с использованием JNI

У меня проблемы с использованием внешних классов Java через JNI. Я проиллюстрирую мою проблему на игрушечном примере.

Это мой класс Java, который в качестве примера использует внешний класс FilenameUtils из Apache Commons IO:

Example.java

import org.apache.commons.io.FilenameUtils;

class Example {

    static void base () {

        String str = "/usr/foo.bar";
        System.out.println("Before");
        try {
            System.out.println(FilenameUtils.getBaseName(str));
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("After");
    }

    public static void main(String[] args) {
        base();
    }   
}

Мой путь к классу устанавливается с помощью $CLASSPATH:

export CLASSPATH=".:/Applications/eclipse/plugins/*"

Я компилирую его с помощью javac, а затем выполняю. Это вывод, который я получаю, и это правильно:

До
Foo
После

Проблема возникает, когда я вызываю Java-метод "base" из C++, используя JNI. Это код C++:

test.cpp

#include <jni.h>
#include <cstring>

int main()
{
    JavaVMOption options[1]; 
    JNIEnv *env;
    JavaVM *jvm;
    JavaVMInitArgs vm_args; 
    jclass cls;
    jmethodID method;
    jobject simpleJNITestInstance;

    options[0].optionString = "-Djava.class.path=.:/Applications/eclipse/plugins/*";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;

    long status = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
    if (status != JNI_ERR)
    {
        cls = env->FindClass("Example");
        if (cls != 0)
        {
            method = env->GetStaticMethodID(cls, "base", "()V");
            env->CallStaticVoidMethod(cls, method, 5);
        }
        jvm->DestroyJavaVM();
    }
    printf("Finished\n");
    return 0;
}

Хотя я не думаю, что это необходимо в моем случае, так как он уже настроен с помощью $CLASSPATH, я снова указал classpath в параметрах VM. Я также добавил параметр 5 в функцию CallStaticVoidMethod, потому что я не знаю, как указать нулевые аргументы. Метод Java не получает никаких аргументов, поэтому это игнорируется.

Затем я компилирую этот код C++:

g++  -o test \
 -I/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/include \
 -I/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/include/darwin \
 -L/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/Contents/Home/jre/lib/server/ \
 test.cpp \
 -ljvm

И выполнить эту скомпилированную программу. Это вывод, который я сейчас получаю:

До
Законченный

Выполнение метода "base" просто останавливается, когда он обращается к методу getBaseName. Никаких исключений не возникает, он просто прекращает выполнение и возвращается к собственному коду.

Почему невозможно выполнить метод FilenameUtils.getBaseName()?

Моя машина работает под управлением Mac OS 10.10 Yosemite, с 64-битной Java 1.7.0.72.

Заранее спасибо.

ОБНОВИТЬ

Я попытался включить commons-io-2.4.jar прямо в classpath, и теперь программа работает:

    options[0].optionString = "-Djava.class.path=.:/Applications/eclipse/plugins/commons-io-2.4/commons-io-2.4.jar";

Теперь мой вопрос: почему classpath ведет себя по-разному при использовании JNI?

1 ответ

Решение

Так что проблема была проста. При указании пути к классу с помощью $CLASSPATH или -cp вы можете использовать подстановочные знаки.

Но если classpath установлен с "-Djava.class.path" подстановочные знаки не работают, список фляг и каталогов должен быть определен индивидуально.

Кроме того, "-Djava.class.path" переопределяет $CLASSPATH.

Другие вопросы по тегам