如何隔离平台特定的JNA绑定?

我有一个项目,我在其中定义了一个JNA包装到Windows kernel32库,在这个库上我做了几个对项目不重要的帮助程序,但增加了与平台的集成(即:使用OutputDebugString + DebugView和Mailslot消息传递function)。

这是我的JNA定义:

 import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import com.sun.jna.Native; import com.sun.jna.ptr.IntByReference; import com.sun.jna.win32.StdCallLibrary; import com.sun.jna.win32.W32APIFunctionMapper; import com.sun.jna.win32.W32APITypeMapper; public interface JnaKernel32 extends StdCallLibrary { //StdCall is needed for lib kernel32 @SuppressWarnings("unchecked") Map ASCII_OPTIONS = new HashMap(){ { put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII); put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII); } }; @SuppressWarnings("unchecked") Map UNICODE_OPTIONS = new HashMap(){ { put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE); put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE); } }; Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS; JnaKernel32 INSTANCE = (JnaKernel32) Native.loadLibrary("kernel32", JnaKernel32.class, DEFAULT_OPTIONS); //some system defines //... } 

和邮筒的定义:

 public class Mailslot { static JnaKernel32 kernel32 = JnaKernel32.INSTANCE; boolean localMailslot = false; int lastError = 0; private int hMailslot = JnaKernel32.INVALID_HANDLE_VALUE; //... } 

而且在一些地方我也有

 static JnaKernel32 kernel32 = JnaKernel32.INSTANCE; //to call OutputDebugString //... kernel32.OutputDebugString("some debug message"); 

我担心的是该项目可以在GNU / Linux或MacOS X上使用,但显然如果在OSX上执行,则Native.loadLibrary在运行时Native.loadLibrary失败。

我正在考虑

  • 使用其他JNA绑定移植本机function
  • 或者只是在另一个平台上运行时禁用现有的Windows kernel32绑定,因为这只是方便而不是强制的帮助。

如何隔离特定于平台的function和调用? 我正在考虑将JNA部分移动到运行时加载的插件?

答案实际上是一个通用的软件开发策略。

  1. 确定您的客户端代码需要的API

    在这种情况下,它可能是MailsSlot.sendMessage(int destID, String msg)

  2. 抽象该API背后的实现细节

    public interface MailSlot { void sendMessage(int destId, String msg); }

  3. 提供一个或多个具体实现来满足API合同

    public class Win32MailSlot implements MailSlot { public void sendMessage(int destId, String msg) { // Do stuff here that's windows-specific } }

    public class OSXMailSlot implements MailSlot { public void sendMessage(int destId, String msg) { // Do stuff here that's windows-specific } }

    在运行时选择适当的实现:

    MailSlot mslot = Platform.IS_WINDOWS ? new Win32MailSlot() : new OSXMailSlot();

经过几次实现之后,您可能会发现一些重复的代码,然后您可能会重构成在特定于平台的实现中共享的抽象基类。

请参阅JNA平台的FileUtils类以获取此类策略的示例。