2014-09-26 47 views
1
不同實現

我必須使用Java JNA來鏈接C庫。這個庫有一個Windows實現和一個Linux實現。這些方法與其他方法有所不同,因爲此方法僅由Windows版本實現。Java JNA根據OS

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

我想只有一個版本,我的Java應用程序,這可能有一個單一的接口與2實現,一個用於Windows操作系統和一個用於Linux操作系統,顯然linux的實施,將有一個空的方法。

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

這工作在Windows中,Linux操作系統在服務啓動時JNA嘗試也覺得在窗口類的本地方法(也如果該類未在運行時使用),所以它拋出一個UnsatifiedLinkError。 如何解決這個僵局? 我真的不能改變本地庫(它會這麼簡單...)

+1

你可以做在本機端的需要進行調整。這將是容易做到像[JavaCPP]工具(https://github.com/bytedeco/javacpp),而不是JNA :) – 2014-09-26 09:18:19

+0

研究「抽象工廠模式」,http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Abstract_Factory – RealHowTo 2014-09-26 22:34:01

回答

0

我解決了使用靜態{}塊。

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

我建議在您的項目中使用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(); 
    } 

} 
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

當在Linux版本上調用Native.loadLibrary時,這會失敗,因爲C庫沒有實現可選方法。 – Tobia 2014-10-03 15:07:36

+0

您需要確保在支持它的平臺上只加載/引用'ExtendedInterface'。 – technomage 2014-10-04 20:03:38