Java JNA根据操作系统的不同实现

时间:2014-09-26 07:27:03

标签: java jna unsatisfiedlinkerror

我必须使用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

这适用于Windows,在Linux操作系统启动时,JNA尝试在Windows类中查找其本机方法(如果此类未在运行时使用),因此会抛出UnsatifiedLinkError。 如何解决这个僵局? 我真的无法改变本机库(它会如此简单......)

3 个答案:

答案 0 :(得分:1)

我建议在项目中使用compilation toolbox来编译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();
    }

}

答案 1 :(得分: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 */
}

答案 2 :(得分:0)

我解决了使用static {}阻止。

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());
        }