java - 如何隔离特定于平台的 JNA 绑定(bind)?

标签 java windows macos jna multiplatform

我有一个项目,我为 Windows kernel32 库定义了一个 JNA 包装器,在此基础上我创建了几个对项目并不重要的帮助程序,但增加了与平台的集成(即:使用 OutputDebugString + DebugView 和 Mailslot 消息传递功能进行系统调试日志记录)。

这是我的 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上使用,但显然,如果Native.loadLibrary在运行时执行,例如在OSX。

我正在考虑

  • 将 native 功能移植到其他 JNA 绑定(bind)
  • 或者在另一个平台上运行时简单地禁用现有的 Windows kernel32 绑定(bind),因为它只是方便但不是强制性的帮助程序。

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

最佳答案

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

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

    在本例中,可能是 MailsS​​lot.sendMessage(int destID, String msg)

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

    公共(public)接口(interface)MailSlot { 无效 sendMessage(int destId, String msg); }

  3. 提供一个或多个具体实现以满足 API 契约(Contract)

    公共(public)类 Win32MailSlot 实现 MailSlot { 公共(public)无效sendMessage(int destId,字符串消息){ //在这里做特定于 Windows 的事情 } }

    公共(public)类 OSXMailSlot 实现 MailSlot { 公共(public)无效sendMessage(int destId,字符串消息){ //在这里做特定于 Windows 的事情 } }

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

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

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

查看 JNA 平台 FileUtils此类策略的示例。

关于java - 如何隔离特定于平台的 JNA 绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28852479/

相关文章:

Python:不在 Windows\System32 中搜索 pythonXX.dll?

macos - Xamarin 中的 MDItem 类

linux - 防止文件系统中的 Unix 域套接字文件在套接字绑定(bind)时被删除

OSX 10.6.4 中的 JAVA 1.5

java - Spring 在使用 find 访问对象时是否应该启动事务?

java - 如何修复java模块之间的循环依赖?

java - Java中去除字符串中的所有空格并将其转换为数组

java - 如何在java中调用重载方法

java - 从批处理脚本创建 jar 文件

windows - 在 Windows 上编译 Clang