如何使用 TypeConverter 通过 JNA 将 C 整数映射到 Java 枚举?
How to map C integer to Java enum via JNA using TypeConverter?
我希望 JNA 自动进行转换。现在我正在遵循第二个答案 in a very similar question and JNA's own EnumConverter 实用程序 class 的解决方案。有一个关键区别,我的枚举有一个构造函数参数。
我的代码定义 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 库以及我的自定义 TypeMapper
的代码。 C 函数 return 一个 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
class:
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)
我已经阅读了文档,对于映射 class 或类型没有任何限制。只有 NativeMapped
接口要求实现者提供 public 无参数构造函数。
是否可以通过这种方式将 C 整数映射到枚举?
更新:
在进一步翻阅 JNA 代码后,我将此字段添加到 SentinelStatus
枚举中:
public final static TypeMapper TYPE_MAPPER = new SentinelTypeMapper();
现在 SentinelLibrary
加载时没有错误。但是所有方法 returning 枚举,return null
错误打印到 stderr
:
JNA: unrecognized return type, size 4
很可能您在库定义的上下文之外定义了 Structure
(这是存储 TypeMapper
信息的地方)。
您可以在您的 Structure
class 上显式设置类型映射器,或者在您的原生 Library
[=51] 中定义您的 Structure
class =].如果没有为 Structure
显式定义 TypeMapper
,它将退回到任何周围 Library
class.
提供的选项
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
class 找不到显式设置的类型映射器时,它会查找包含 Library
类型的 class,并尝试查找实例化 class 时使用的选项。这些选项在加载本机库时会被缓存,因此可以使用 Library
subclass 作为键通过键查找获得这些选项。您需要实现 Library
接口,以便您的直接映射库被识别为本机库 class.
编辑
这是 JNA 类型映射器处理中的错误(请参阅 project issue)。这似乎仅限于直接映射库和 enum
类型映射。
编辑
这里有几个 JNA 错误,如果您想尝试,请 fix is available。此问题与直接映射库上的类型映射器隔离,在该库中,基元被转换为 Java 对象。
我希望 JNA 自动进行转换。现在我正在遵循第二个答案 in a very similar question and JNA's own EnumConverter 实用程序 class 的解决方案。有一个关键区别,我的枚举有一个构造函数参数。
我的代码定义 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 库以及我的自定义 TypeMapper
的代码。 C 函数 return 一个 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
class:
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)
我已经阅读了文档,对于映射 class 或类型没有任何限制。只有 NativeMapped
接口要求实现者提供 public 无参数构造函数。
是否可以通过这种方式将 C 整数映射到枚举?
更新:
在进一步翻阅 JNA 代码后,我将此字段添加到 SentinelStatus
枚举中:
public final static TypeMapper TYPE_MAPPER = new SentinelTypeMapper();
现在 SentinelLibrary
加载时没有错误。但是所有方法 returning 枚举,return null
错误打印到 stderr
:
JNA: unrecognized return type, size 4
很可能您在库定义的上下文之外定义了 Structure
(这是存储 TypeMapper
信息的地方)。
您可以在您的 Structure
class 上显式设置类型映射器,或者在您的原生 Library
[=51] 中定义您的 Structure
class =].如果没有为 Structure
显式定义 TypeMapper
,它将退回到任何周围 Library
class.
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
class 找不到显式设置的类型映射器时,它会查找包含 Library
类型的 class,并尝试查找实例化 class 时使用的选项。这些选项在加载本机库时会被缓存,因此可以使用 Library
subclass 作为键通过键查找获得这些选项。您需要实现 Library
接口,以便您的直接映射库被识别为本机库 class.
编辑
这是 JNA 类型映射器处理中的错误(请参阅 project issue)。这似乎仅限于直接映射库和 enum
类型映射。
编辑
这里有几个 JNA 错误,如果您想尝试,请 fix is available。此问题与直接映射库上的类型映射器隔离,在该库中,基元被转换为 Java 对象。