2014-12-07 4 views
1

У меня возникли проблемы с использованием внешних классов 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 от 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, я снова указали путь к классам в 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 

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

Перед
Готовые

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

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

Моя машина Mac OS 10.10 Yosemite, с Java 1.7.0.72 64 бит.

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

UPDATE

Я попытался включая Викисклад Io-2.4.jar непосредственно в пути к классам, и теперь программа работает:

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

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

ответ

1

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

Но если путь к классам задан с помощью «-Djava.class.path», подстановочные знаки не работают, список банок и каталогов должен быть указан отдельно.

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