我从项目中提取了以下 C 头文件,我想使用 JNA 将其映射到 Java:
...
typedef size_t ObjectHandle;
typedef const char *FfiStr;
typedef struct FfiList_FfiStr {
size_t count;
const FfiStr *data;
} FfiList_FfiStr;
typedef struct FfiList_FfiStr FfiStrList;
int create_schema(FfiStr schema_name,
FfiStr schema_version,
FfiStr issuer_id,
FfiStrList attr_names,
ObjectHandle *result_p);
...
我找不到 FfiStr 和 FfiStrList 类型到 Java 的正确映射。
这是我在 Java 中尝试过的映射:
public interface CredLibrary extends Library {
CredLibrary INSTANCE = (CredLibrary) Native.load("credlibrary", CredLibrary.class);
public class FfiStr extends Structure {
public class ByReference extends FfiStr implements Structure.ByReference {};
public String FfiStr;
public FfiStr(){
FfiStr= new String();
}
public FfiStr(String s) {
FfiStr = new String(s);
}
@Override
protected List getFieldOrder() {
return Arrays.asList("FfiStr");
}
}
public class FfiList_FfiStr extends Structure{
public Size_t count;
public FfiStr.ByReference[] data;
public FfiList_FfiStr(String[] attr){
super();
count = new Size_t(attr.length);
data= new FfiStr.ByReference[attr.length];
}
@Override
protected List getFieldOrder() {
return Arrays.asList("count", "data");
}
}
int create_link_secret(PointerByReference link_secret_p);
int generate_nonce(PointerByReference nonce_p);
int create_schema(FfiStr schema_name, FfiStr schema_version, FfiStr issuer_id,FfiList_FfiStr attr_names, IntByReference result_p);
}
第一个 create_link_secret 和generate_nonce 函数工作正常,create_schema 不起作用。
这是我尝试过的测试:
CredLibrary.FfiStr schema_name= new CredLibrary.FfiStr("test");
CredLibrary.FfiStr schema_version = new CredLibrary.FfiStr("v1");
CredLibrary.FfiStr issuer_id =new CredLibrary.FfiStr( "123");
CredLibrary.FfiList_FfiStr attrib = new CredLibrary.FfiList_FfiStr(attr);
IntByReference pref3= new IntByReference();
int c= lib.anoncreds_create_schema(schema_name,schema_version,issuer_id,attrib,pref3);
int p3 =pref3.getValue();
Log.i("TEST","Value of the schema created:"+String.valueOf(c));
更准确地说,create_schema 输出 1,这是输入值相关问题的 ErrorCode 值。所以这可能意味着我从 C 到 Java 的结构之间的映射不正确。所以我可能在 Java 映射代码中做错了什么。
可以指出我做错了什么吗?
我想也许 FfiStr 是错误的,因为 Java FfiStr 有一个属性,而 C 没有。
C
const char *
映射到 Java String
。 JNA 有 size_t
的映射,具体取决于您的操作系统。
您通常不需要也不应该添加
ByReference
标签。这些增加了另一层指针间接寻址,这通常是错误的。内联结构中您不需要指针,JNA 默认为 ByValue。作为函数/方法参数,您通常需要指针,而 JNA 在这里默认为 ByReference。
您的结构中确实有一个字符串数组,但 JNA 要求在初始化时声明数组长度。如果您在 Java 端声明它,那么这是可行的,但如果从本机端读取它,则需要一些额外的步骤来覆盖结构上的
read()
。
您可以删除
FfiStr
结构并使用 String
进行该映射。
String
如果您决定将字符串包装在结构中(例如,为了类型安全),请不要在其上使用
ByReference
,因为String
映射已经包含指针。此映射本质上与键入的 String
: 相同
@FieldOrder ({"FfiStr"})
public class FfiStr extends Structure {
public String FfiStr;
public FfiStr(String s) {
FfiStr = s;
}
}
对于你的第二个结构,它有点复杂。当声明一个Structure时,JNA为其分配内存,因此它需要知道数组的大小。所以你需要给数据一个非零的初始化,然后在构造函数中覆盖该值并重新分配内存:
@FieldOrder ({"count", "data"})
public class FfiList_FfiStr extends Structure{
public Size_t count;
public String[] data = new String[1];
public FfiList_FfiStr(String[] attr){
count = new Size_t(attr.length);
data = new String[attr.length];
// or new FfiStr[attr.length]; if defined above
allocateMemory();
}
// if reading from native you'll need to override read()
// to do similar memory reallocation
}