Работа с libpath с java отражением - PullRequest
0 голосов
/ 24 мая 2010

Я динамически загружаю класс и вызываю метод для него.Этот класс делает JNI.Когда я вызываю класс, Java пытается загрузить библиотеку.Это вызывает ошибку, потому что библиотека не находится в libpath.Вместо этого я звоню из jar, поэтому не могу легко изменить libpath (тем более что библиотека не находится в том же каталоге или подкаталоге jar).Я знаю путь к библиотеке, но как ее загрузить, прежде чем загружать класс.

Текущий код:

public Class<?> loadClass(String name) throws ClassNotFoundException {
    if(!CLASS_NAME.equals(name))
            return super.loadClass(name);

    try {
        URL myUrl = new URL(classFileUrl);
        URLConnection connection = myUrl.openConnection();
        InputStream input = connection.getInputStream();
        byte[] classData = readConnectionToArray(input);

        return defineClass(CLASS_NAME,
                classData, 0, classData.length);

    } catch (MalformedURLException e) {
        throw new UndeclaredThrowableException(e);
    } catch (IOException e) {
        throw new UndeclaredThrowableException(e); 
    }
}

Исключение:

Can't find library libvcommon.so
java.lang.UnsatisfiedLinkError: vcommon (A file or directory in the path name does not exist.)
        at java.lang.ClassLoader.loadLibraryWithPath(ClassLoader.java:998)
        at java.lang.ClassLoader.loadLibraryWithClassLoader(ClassLoader.java:962)
        at java.lang.System.loadLibrary(System.java:465)
        at vcommon.(vcommon.java:103)
        at java.lang.J9VMInternals.initializeImpl(Native Method)
        at java.lang.J9VMInternals.initialize(J9VMInternals.java:200)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
        at java.lang.reflect.Method.invoke(Method.java:599)
        at com.fortune500.fin.v.vunit.reflection.ReflectionvProcessor.calculateV(ReflectionvProcessor.java:36)
        at com.fortune500.fin.v.vunit.UTLTestCase.execute(UTLTestCase.java:42)
        at com.fortune500.fin.v.vunit.TestSuite.execute(TestSuite.java:15)
        at com.fortune500.fin.v.vunit.batch.Testvendor.execute(Testvendor.java:101)
        at com.fortune500.fin.v.vunit.batch.Testvendor.main(Testvendor.java:58)

Редактировать: У меня сейчас проблема 64-битная или 32-битная.Я вернусь к этому, когда разберусь с этим.

Related: Динамическая загрузка класса в Java с другим именем пакета

1 Ответ

1 голос
/ 24 мая 2010

Если вы знаете путь к библиотеке, вы можете добавить путь к переменной среды java.library.path в своем загрузчике пользовательских классов. Более простой подход - вычислить путь и использовать его при вызове Runtime.loadLibrary.

Приведенный ниже код описывает два подхода: использование loadLibrary и установка системного свойства java.library.path.

 if(CLASS_NAME.equals(name)) {

    // two ways of doing this - either load the library explicitly from the full path  
    if (useFullPath) {
      Runtime.getRuntime().loadLibrary("/full/path/to/mylibrary");
    }
    else { // or tweaking the library path
      System.setProperty("java.library.path", 
         System.getProperty("java.library.path")
         + System.getProperty("file.separator")
         + "/path/to/lib");
    }
 }
 return super.loadClass(name);

Вы упоминаете, что ваш код вызывается из jar - использование пользовательского загрузчика классов будет затруднено, если ClassLoader также является частью jar. Вы убедились, что ваш загрузчик классов действительно используется?

Более простой подход - изменить текущий вызов loadLibrary в вашем родном классе, чтобы использовать полный путь. Например. получить из системных свойств или вычислить его, если вы заранее знаете, где его найти. Конечно, это только вариант, если у вас есть исходный код для нативного класса. Если вы не можете изменить собственный класс, используйте вызов loadLibrary в загрузчике классов.

Насколько я понимаю, вызовы для загрузки библиотеки с одинаковым именем библиотеки (независимо от пути) загружают одну и ту же библиотеку. (По крайней мере, это поведение в Windows - я не проверял в Linux.) Таким образом, хотя загрузчик классов загружает библиотеку, используя полный путь, а собственный класс загружает библиотеку, используя ее простое имя, оба должны быть преобразованы в та же библиотека.

(Просто для полноты, разрешение эквивалентных библиотек происходит в ядре, опять же, исходя из опыта Win32. Каждая библиотека внутренне имеет имя, и Windows загружает только один экземпляр библиотеки с тем же внутренним именем на процесс.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...