JNA Structure.getFieldOrder() 不匹配声明的字段名称

JNA Structure.getFieldOrder() does not match declared field names

我在结构内部定义 JNA 结构时遇到以下异常:

Exception in thread "main" java.lang.Error: Structure.getFieldOrder() on class com.MyInterface$mine$ByReference returns names ([color, data, hello, rice, str, wild]) which do not match declared field names

查看我的 Cpp 结构:

typedef struct s_mine
{
    e_color           color;    //e_color is enum type made of int values
    his               data;        
    int               str;        
    unsigned int      wild;         
    unsigned int      hello;        
    float             rice; 
} mine;

typedef struct s_his
{
    unsigned char * data; 
    unsigned int    size; 
} his;

请参阅下面的示例,即 MyInterface.java:

public interface MyInterface extends Library {

    public static class his extends Structure {
        public static class ByReference extends his implements Structure.ByReference {} // Need the stucture address as it a parameter of a particular wrapped method
        public static class ByValue extends his implements Structure.ByValue {}         // Need the structure value inside "mine" Structure
        public Pointer data;
        public int size;
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] { "data", "size"});
        }
    }
    
    public class mine extends Structure {
        public static class ByReference extends mine implements Structure.ByReference {}
        int color; 
        his.ByValue data;
        int str; 
        int wild; 
        int hello; 
        float rice;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[] {"color","data","str","wild","hello","rice"});
        }
    }
}

使用 MyInterface 的主要 class 包含以下行,其中关于“我的”结构字段的顺序我有例外:

final MyInterface.mine.ByReference mine_ref = new MyInterface.mine.ByReference();   

因此我调试代码以便在 Structure.class 之后进入 JNA 进入以下 getFields 方法(我在其中得到异常(下面的第二个):

    protected List<Field> getFields(boolean force) {
        List<Field> flist = getFieldList();
        Set<String> names = new HashSet<String>();
        for (Field f : flist) {
            names.add(f.getName());
        }

        List<String> fieldOrder = fieldOrder();
        if (fieldOrder.size() != flist.size() && flist.size() > 1) {
            if (force) {
                throw new Error("Structure.getFieldOrder() on " + getClass()
                                + (fieldOrder.size() < flist.size()
                                    ? " does not provide enough"
                                    : " provides too many")
                                + " names [" + fieldOrder.size()
                                + "] ("
                                + sort(fieldOrder)
                                + ") to match declared fields [" + flist.size()
                                + "] ("
                                + sort(names)
                                + ")");
            }
            return null;
        }

        Set<String> orderedNames = new HashSet<String>(fieldOrder);
        if (!orderedNames.equals(names)) {
            throw new Error("Structure.getFieldOrder() on " + getClass()
                            + " returns names ("
                            + sort(fieldOrder)
                            + ") which do not match declared field names ("
                            + sort(names) + ")");
        }

        sortFields(flist, fieldOrder);
        return flist;
    }

这就是我在 getFields 方法中引发异常时探索以下字段值的结果

fieldOrder = [color, data, str, wild, hello, rice]
orderedNames = [str, color, data, hello, rice, wild]

由于名称为空而引发异常。无论如何,由于 HashSet java.util class 不能保证顺序随时间保持不变,我肯定认为 JNA Structure.java 中存在错误。 因为我的 fieldOrder 的顺序是按 new HashSet<String>(fieldOrder) 指令随机排序的,因此与 orderedNames 的顺序不同。

  1. 是否有人同意我的观点,或者我是否遗漏了关于声明和使用我的 JNA 结构的方式?

  2. 如果没有错误(即故意使用 HashSet...),我是不是在声明我的结构时出错了?我该如何解决这个问题?

您的错误在 mine 结构中:您需要将字段声明为 public。 JNA 使用反射并依赖 public 修饰符来映射到本机的字段;否则它们只是 class.

中的辅助字段

否则,映射会像您拥有的那样工作,但请考虑以下改进:

  • 当用作嵌套结构时,您不需要使用结构的 ByValue 版本。这是默认设置。唯一需要对嵌套结构采取特殊操作的情况是它是 ByReference
    • 同样,当用作函数参数时,ByReference 是默认值。仅当函数需要 ByValue 参数时才需要特殊处理。
  • getFieldOrder() 覆盖的使用在 JNA 5.x 中被替换为 @FieldOrder 注释。虽然您的工作有效,但如果您将该注释放在结构之前,您的代码将更具可读性,例如,
@FieldOrder({"data", "size"})
class his extends Structure { 
  // etc... 
}
  • 接口variables/classes/etc。默认情况下是 publicstaticfinal,因此使用这些修饰符是多余的。