如何隔离平台特定的 JNA 绑定?
how to isolate JNA bindings that are platform specific?
我有一个项目,我在其中为 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.
我正在考虑
- 使用其他 JNA 绑定移植本机功能
- 或者在另一个平台上 运行 时简单地禁用现有的 Windows kernel32 绑定,因为它只是方便而不是强制性的助手。
如何隔离特定于平台的功能和进行的调用?我可能正在考虑将 JNA 部分移动到运行时加载的插件?
答案真是一个通用的软件开发策略。
确定您的客户端代码需要的 API
在这种情况下,它可能是 MailsSlot.sendMessage(int destID, String msg)
抽象出其背后的实现细节API
public interface MailSlot {
void sendMessage(int destId, String msg);
}
提供一个或多个具体实现以满足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();
在一些实现之后,您可能会发现一些重复的代码,然后您可以将其重构为在特定于平台的实现之间共享的抽象基础 class。
有关此类策略的示例,请参阅 JNA 平台 FileUtils
class。
我有一个项目,我在其中为 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.
我正在考虑
- 使用其他 JNA 绑定移植本机功能
- 或者在另一个平台上 运行 时简单地禁用现有的 Windows kernel32 绑定,因为它只是方便而不是强制性的助手。
如何隔离特定于平台的功能和进行的调用?我可能正在考虑将 JNA 部分移动到运行时加载的插件?
答案真是一个通用的软件开发策略。
确定您的客户端代码需要的 API
在这种情况下,它可能是
MailsSlot.sendMessage(int destID, String msg)
抽象出其背后的实现细节API
public interface MailSlot { void sendMessage(int destId, String msg); }
提供一个或多个具体实现以满足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();
在一些实现之后,您可能会发现一些重复的代码,然后您可以将其重构为在特定于平台的实现之间共享的抽象基础 class。
有关此类策略的示例,请参阅 JNA 平台 FileUtils
class。