我想让JNA自动进行转换。现在,我在一个非常类似的问题以及JNA自己的EnumConverter实用程序类中,按照第二个答案的解决方案进行操作。有一个关键的区别,我的枚举有一个构造函数参数。
我的代码定义TypeConverter
:
public class SentinelStatusConverter implements TypeConverter {
@Override
public SentinelStatus fromNative(Object nativeValue, FromNativeContext context) {
Integer code = (Integer) nativeValue;
return SentinelStatus.fromCode(code);
}
@Override
public Integer toNative(Object value, ToNativeContext context) {
SentinelStatus status = (SentinelStatus) value;
return Integer.valueOf(status.getCode());
}
@Override
public Class<Integer> nativeType() {
return Integer.class;
}
}
public class SentinelTypeMapper extends DefaultTypeMapper {
public SentinelTypeMapper() {
addTypeConverter(SentinelStatus.class, new SentinelStatusConverter());
}
}
这是直接将本地C库与我的custom一起注册的代码TypeMapper
。C函数返回一个int
我想自动映射到SentinelStatus
枚举的函数:
public class SentinelLibrary {
static {
Map<String, Object> options = new HashMap<String, Object>();
options.put(Library.OPTION_TYPE_MAPPER, new SentinelTypeMapper());
Native.register(NativeLibrary.getInstance("libnamelib", options));
}
public static native SentinelStatus hasp_get_sessioninfo(
NativeLong sessionHandle,
String query,
PointerByReference info);
}
SentinelStatus
是enum
像这样:
public enum SentinelStatus {
HASP_STATUS_OK(0),
HASP_SOME_ERROR(13),
...
HASP_NOT_IMPL(1831);
private final int code;
SentinelStatus(final int code) { this.code = code; }
public int getCode() { return this.code; }
public static SentinelStatus fromCode(final int code) {
for (SentinelStatus status : EnumSet.allOf(SentinelStatus.class)) {
if (code == status.getCode()) {
return status;
}
}
return SentinelStatus.HASP_NOT_IMPL;
}
}
使用此JNA映射和转换器,每当尝试加载SentinelLibrary
类时都会收到错误消息:
java.lang.ExceptionInInitializerError
...
Caused by: java.lang.IllegalArgumentException: Unsupported Structure field type class package.name.SentinelStatus
at com.sun.jna.Structure$FFIType.get(Structure.java:1851)
at com.sun.jna.Structure$FFIType.get(Structure.java:1806)
at com.sun.jna.Native.register(Native.java:1438)
at com.sun.jna.Native.register(Native.java:1165)
at package.name.SentinelLibrary.<clinit>(line with Native.register() call)
我已经阅读了文档,对映射的类或类型没有任何限制。仅NativeMapped
接口需要实现者提供公共的无参数构造函数。
是否可以通过这种方式将C整数映射到枚举?
更新:在进一步遍历JNA代码之后,我将此字段添加到了SentinelStatus
枚举中:
public final static TypeMapper TYPE_MAPPER = new SentinelTypeMapper();
现在SentinelLibrary
被加载而没有错误。但是所有返回枚举的方法都返回null
错误,并输出到stderr
:
JNA: unrecognized return type, size 4
您很可能Structure
在库定义(在其中TypeMapper
存储信息)的上下文之外定义自己。
您可以在类中显式设置类型映射器Structure
,也可以Structure
在本机Library
类中定义类。如果没有为TypeMapper
明确定义Structure
,它将退回到任何周围Library
类提供的选项。
public class MyStructure extends Structure {
public MyStructure() {
setTypeMapper(new MyTypeMapper());
}
}
或者,
public interface MyLibrary extends Library {
public class MyStructure extends Structure {
}
}
或使用直接映射:
public class MyLibrary implements Library {
{ Native.register(...); }
public class MyStructure extends Structure { }
}
当Structure
类无法找到显式设置的类型映射器时,它将查找类型为的封闭类Library
,并尝试查找实例化该类时使用的选项。这些选项在加载本机库时被缓存,因此可以通过使用Library
子类作为键的键查找来使用。您将需要实现Library
接口,以便将直接映射的库识别为本地库类。
编辑
这是JNA的类型映射器处理中的错误(请参阅项目问题)。这似乎仅限于直接映射的库和enum
类型映射。
编辑
这里有几个JNA错误正在起作用,如果您想尝试的话,可以使用一个修复程序。此问题仅在将原语转换为Java对象的直接映射库上的类型映射器中存在。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句