从C++获取Java中的Struct对象

问题描述 投票:0回答:3

我有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 )
    {

    }
}

我想知道

  1. 我可以做一些我做的事情吗
    env->CallObjectMethod( clazzObject, clazzMethod, args );
    ,我的意思是我可以将 struct 对象作为参数传递给 CallObjectMethod 吗?
  2. 如何在Java代码func中获取struct对象?
java android java-native-interface
3个回答
1
投票

你不能。假设您实际上需要在 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
。)


0
投票

您可以这样做,但您必须自己映射这些值。你应该看看这个问题:如何在 JNI 中将 C 结构体来回传递给 Java 代码?.


0
投票

你可以尝试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;
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.