Java JNA Различные реализации в зависимости от ОС

1

Я должен использовать Java JNA для связывания библиотеки C. Эта библиотека имеет реализацию Windows и Linux. Они отличаются друг от друга для одного метода, потому что этот метод реализуется только версией Windows.

MyJnaInterface INSTANCE = (MyJnaInterface) Native.loadLibrary("MyLibrary",
                MyJnaInterface.class);

Я хотел бы иметь только одну версию моего Java-приложения, у этого может быть один интерфейс с 2-мя реализациями: один для windows os и один для linux os, очевидно, что реализация linux будет иметь пустой метод.

public interface MyJnaInterface
public class MyJnaWinImpl implements MyJnaInterface
public class MyJnaLinuxImpl implements MyJnaInterface

Это работает в окнах, в ОС Linux при запуске службы. JNA пытается найти свои собственные методы также в классах Windows (также если этот класс не используется во время выполнения), и поэтому он выдает UnsatifiedLinkError. Как решить этот тупик? Я действительно не могу изменить родную библиотеку (было бы так просто...)

  • 1
    Вы можете внести необходимые изменения на родной стороне ... Это было бы легко сделать с помощью такого инструмента, как JavaCPP вместо JNA :)
  • 0
    Изучите "Абстрактный шаблон фабрики", en.wikibooks.org/wiki/Computer_Science_Design_Patterns/…
Теги:
jna
unsatisfiedlinkerror

3 ответа

0
Лучший ответ

Я решил использовать static {} block.

public interface MyJnaInterface;
public interface MyJnaInterfaceWin implements MyJnaInterface; // this has the WinMethod method

...

    private static MyJnaInterface INSTANCE;

    static{
        if(SystemUtils.IS_OS_LINUX){
            INSTANCE=(MyJnaInterface) Native.loadLibrary("MyLibrary",MyJnaInterface.class);
        }else{
            INSTANCE=(MyJnaInterfaceWin) Native.loadLibrary("MyLibrary",MyJnaInterfaceWin.class);
        }
    }


...

public static void WinMethod(){
            if(!SystemUtils.IS_OS_LINUX) ((MyJnaInterfaceWin)INSTANCE).WinMethod());
        }
1

Я предлагаю использовать панель инструментов компиляции в вашем проекте для компиляции исполняемого файла Java-кода в зависимости от значения, возвращаемого System.getProperty("os.name"). Если он возвращает окна, вы можете добавить исходный код для MyJnaWinImpl в одну строку и передать это в класс JavaSourceCompiler. После этого компилируется класс нагрузки и создайте экземпляр. На linux JavaSourceCompiler скомпилирует MyJnaLinuxImpl. Убедитесь, что перед созданием этого экземпляра загружаются библиотеки.

Ниже приведен небольшой фрагмент кода.

package test;

import org.abstractmeta.toolbox.compilation.compiler.*;
import org.abstractmeta.toolbox.compilation.compiler.impl.*;
import java.lang.ClassLoader;;


public class test {

    public static void main(String[] args) throws ClassNotFoundException,InstantiationException,IllegalAccessException{
        JavaSourceCompiler javaSourceCompiler = new JavaSourceCompilerImpl();
        JavaSourceCompiler.CompilationUnit compilationUnit = javaSourceCompiler.createCompilationUnit();
        String os = System.getProperty("os.name");
        String SourceCode;
        if ( os.contentEquals("Windows"))
        {
           SourceCode =  "package com.test.foo;\n" +
          "import MyJnaInterface.*;" +
          "import MyJnaWinImpl " +
          "public class Foo implements MyJnaWinImpl  {\n" +
          " public native void check();\n" +
          "    }";
        }
        else
        {
               SourceCode =  "package com.test.foo;\n" +
                          "import MyJnaInterface.*;" +
                          "import MyJnaLinuxImpl  " +
                          "public class Foo implements MyJnaLinuxImpl   {\n" +
                          //" public native void check();\n" +
                          "    }";  
        }
        compilationUnit.addJavaSource("com.test.foo.Foo", SourceCode);
        ClassLoader classLoader = javaSourceCompiler.compile(compilationUnit);
        Class fooClass = classLoader.loadClass("com.test.foo.Foo");
        Object foo = fooClass.newInstance();
    }

}
0

Я предполагаю, что вы используете прямое сопоставление, поскольку сопоставление интерфейсов не будет искать вашу функцию до тех пор, пока вы ее не вызовете.

Напишите базовый класс с базовой реализацией, а затем производный класс, который включает дополнительное сопоставление. Загружайте только производный класс, где вы знаете, что существует базовая функция.

class BaseInterface { 
    public native void nativeMethod();
    public void extendedMethod() { /* empty stub */ }
}

class ExtendedInterface extends BaseInterface {
    public native void extendedMethod();
}

if (needExtendedInterface) {
    lib = /* load extended library */
}
else {
    lib = /* load base library */
}
  • 0
    Когда вызывается Native.loadLibrary на версии Linux, это не удается, потому что библиотека C не реализует дополнительный метод.
  • 0
    Вы должны убедиться, что вы загружаете / ссылаетесь на ExtendedInterface тогда, когда находитесь на платформе, которая его поддерживает.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню