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 的顺序不同。
是否有人同意我的观点,或者我是否遗漏了关于声明和使用我的 JNA 结构的方式?
如果没有错误(即故意使用 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。默认情况下是
public
、static
和 final
,因此使用这些修饰符是多余的。
我在结构内部定义 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 的顺序不同。
是否有人同意我的观点,或者我是否遗漏了关于声明和使用我的 JNA 结构的方式?
如果没有错误(即故意使用 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。默认情况下是
public
、static
和final
,因此使用这些修饰符是多余的。