如何使用TypeConverter通过JNA将C整数映射到Java枚举?

托马斯·库齐沃

我想让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一起注册的代码TypeMapperC函数返回一个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);
}

SentinelStatusenum像这样:

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章