2014-09-26 2 views
1

Java JNA를 사용하여 C 라이브러리를 연결해야합니다. 이 라이브러리에는 Windows 구현과 Linux 구현이 있습니다. 이 메서드는 Windows 버전에서만 구현되므로 이러한 메서드는 단일 메서드와 다릅니다. 내 Java 응용 프로그램의 한 버전을 가지고 싶습니다Java JNA OS에 따라 다른 구현

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

이 분명히 리눅스 구현이 비어있는 방법이있을 것이다, 2 구현, 윈도우 운영 체제 용 및 리눅스 운영 체제에 대한 하나 하나의 인터페이스를 가질 수있다.

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

이것은 JNA (이 클래스는 런타임에 사용되지도 경우) 그래서이 UnsatifiedLinkError가 발생 창 클래스도 네이티브 방법을 찾으려고 서비스 시작에 리눅스 OS에서, 윈도우에서 작동합니다. 이 교착 상태를 해결하는 방법은 무엇입니까? 정말 네이티브 라이브러리를 변경할 수 없습니다. (매우 간단합니다 ...)

+1

당신은 기본 측면에 필요한 조정을 ... 이것은 [JavaCPP]와 같은 도구를 쉽게 할 수있을 것입니다 수 (https://github.com/bytedeco/javacpp) 대신 JNA의 : –

+0

"Abstract Factory Pattern"연구, http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Abstract_Factory – RealHowTo

답변

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 프로젝트에 System.getProperty ("os.name")에 의해 반환 된 값에 따라 Java 코드 런타임을 컴파일하는 것이 좋습니다. . 창을 반환하면 한 문자열에 MyJnaWinImpl의 소스 코드를 추가하고이를 JavaSourceCompiler 클래스에 전달할 수 있습니다. 일단 컴파일 된로드 클래스 및 인스턴스를 만듭니다. 리눅스에서 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

+0

지원하는 플랫폼에서 'ExtendedInterface'만로드/참조하도록해야합니다. – technomage