我有C++结构:
typedef struct FunctionArgs
{
char* url;
char* info;
int id;
bool isWorking;
}
还有 C++ 函数,它作为参数获取
FunctionArgs
结构,现在我想从此函数调用 Java 方法,并作为该方法的参数给出 FunctionArgs
结构。
void func( const FunctionArgs& args )
{
// Do some code ...
env->CallObjectMethod( clazzObject, clazzMethod, args );
}
正如您在
env->CallObjectMethod( clazzObject, clazzMethod, *args );
函数中看到的那样,作为第三个参数,我给出 args
,它是 FunctionArgs
结构对象。
在JAVA我有类和函数:
class JFunctionArgs
{
String url;
String info;
int id;
boolean isWorking;
}
public class SomeClass
{
public void func( JFunctionArgs args )
{
}
}
env->CallObjectMethod( clazzObject, clazzMethod, args );
,我的意思是我可以将 struct 对象作为参数传递给 CallObjectMethod 吗?你不能。假设您实际上需要在 Java 和 C 中使用这些数据,您将需要在 Java
Object
和 C struct
之间进行编组。
在 JNI 代码中,您需要创建一个新的 Java 对象并填充其数据。例如:
jclass clazz = env->FindClass("JFunctionArgs");
jmethodID ctor = env->GetMethodID(clazz, "<init>", "()V");
jobject obj = env->NewObject(clazz, ctor);
jfieldID urlField = env->GetFieldID(clazz, "url", "Ljava/lang/String;");
env->SetObjectField(obj, urlField, env->NewString(functionArgs.url));
...等等
(但是,如果您只需要在 C 中修改
struct
的数据,则可以简单地返回指向它的指针,并将其视为 Java 中的不透明 long
。)
您可以这样做,但您必须自己映射这些值。你应该看看这个问题:如何在 JNI 中将 C 结构体来回传递给 Java 代码?.
你可以尝试Magic-byte
可以将byte[]解析为Java对象;
示例:
// step1. deinfe class like struct
// declare class should be public
@MagicClass(byteOrder = ByteOrder.BIG_ENDIAN)
public class School {
// 10 byte, default use ASCII encoding
@MagicField(order = 1, size = 10)
private String name;
// 2 byte, this field will be fill actually all data size length
@MagicField(order = 3, calcLength = true)
private short length;
// this field ref Student class
// totalBytes = students.bytes * length
@MagicField(order = 5, size = 2)
private Student[] students;
// 0 byte, can't recognize this type, so it will be ignore
@MagicField(order = 7)
private List<Object> notSupport;
// 0 byte, ignore
@MagicField(order = 9)
private Object age;
// 4 byte, size = 4 means use 4 bytes, and timestamp will cast to seconds
@MagicField(order = 13, size = 4, timestampFormat = TimestampFormatter.TO_TIMESTAMP_SECONDS)
private Date[] birthdays;
// 1 byte, define order not equals actually order
@MagicField(order = 15)
private byte age;
// 1 byte
@MagicField(order = 17)
private byte checkCode;
// getter and setter ...
}
@MagicClass()
public class Student {
// 10 byte
@MagicField(order = 1, size = 10)
private String name;
// 4 byte,
@MagicField(order = 5)
private int length;
// totalBytes = phones.size * length
// unit 8 byte, the list size equals length value
@MagicField(order = 10, dynamicSizeOf = 5)
private List<Long> phones;
// 1 byte
@MagicField(order = 15)
private byte age;
// use 4 bytes, default 6 bytes
@MagicField(order = 18, size = 4, timestampFormat = TimestampFormatter.TO_TIMESTAMP_SECONDS)
private Date birthDay;
// getter and setter ...
}
public class Hello {
void main() {
// config the data checker logic
MagicByte.configMagicChecker(Checker::customChecker);
School school = new School();
school.setAge((byte) 23);
// you can set other propertis
// object to bytes
// you also set checker when you call unpack method
byte[] bytes = MagicByte.unpack(school, Checker::customChecker);
School school2 = MagicByte.pack(bytes, School.class); // bytes to object
System.out.println(school.getAge() == school2.getAge()); // out put true
}
}
public class Checker {
/**
* the data is all of the bytes data
* @param data
* @return
*/
public static long customChecker(byte[] data) {
return 0xff;
}
}