使用 JNI 创建、填充和返回 Java 类实例

2022-09-04 22:12:53

我正在尝试使用 JNI 函数来创建一个 Java 类,并使用 DeviceId.java 构造函数方法设置该类的一些属性。我能够使用GetMethodID获取构造函数方法,但是我如何创建一个新的 Device实例.java然后设置属性(setId和setCache)。目标是将设备.java对象的完全填充实例返回给调用方。有什么想法吗?

JNI 函数:

 JNIEXPORT jobject JNICALL Java_com_test_getID(JNIEnv *env, jclass cls) 
    {
        jmethodID cnstrctr;
        jclass c = (*env)->FindClass(env, "com/test/DeviceId");
        if (c == 0) {
            printf("Find Class Failed.\n");
         }else{
            printf("Found class.\n");
         }

        cnstrctr = (*env)->GetMethodID(env, c, "<init>", "(Ljava/lang/String;[B)V");
        if (cnstrctr == 0) {
            printf("Find method Failed.\n");
        }else {
            printf("Found method.\n");
        }

        return (*env)->NewObject(env, c, cnstrctr);
    }

Java 类:

package com.test;

public class DeviceId {
    private String id;
    private byte[] cache;

        public DeviceId(){}
    public DeviceId(String id, byte[] cache){
        this.id=id;
        this.cache=cache;
    }

    public byte[] getCache() {
        return cache;
    }

    public void setCache(byte[] cache) {
        this.cache = cache;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }   
}

答案 1

调用 时,您提供了双参数构造函数的签名。因此,您只需要在调用时传递您的和 a - 例如:GetMethodIDjstringjbytearrayNewObject

return (*env)->NewObject(env, c, cnstrctr, id, cache);

除非您决定调用 0-arg 构造函数,否则您不需要调用 and 方法 - 这只会使您的代码复杂化,因为您必须调用这些方法并调用它们。沿着你所在的路线继续前进更简单。setIdsetCacheGetMethodID


答案 2

我想将一个自定义Java对象从JNI的cpp代码返回给Java。解决方案是返回一个 from cpp 函数,并在本机方法声明中使用我们的自定义 Java 对象。jobject

public class PyError {

    public String message;

    public boolean occurred;

    public PyError(boolean occurred, String message){
        this.message = message;
        this.occurred = occurred;
    }
} 

和 Java 中的方法声明:

native PyError nativePythonErrorOccurred();

在cpp方面:

extern "C" JNIEXPORT jobject JNICALL
Java_com_your_package_nativePythonErrorOccurred(JNIEnv *env, jobject obj) {

    jclass javaLocalClass = env->FindClass("com/your/package/PyError");

    if (javaLocalClass == NULL) {
        LOGP("Find Class Failed.\n");
    } else {
        LOGP("Found class.\n");
    }

    jclass javaGlobalClass = reinterpret_cast<jclass>(env->NewGlobalRef(javaLocalClass));

    // info: last argument is Java method signature
    jmethodID javaConstructor = env->GetMethodID(javaGlobalClass, "<init>", "(ZLjava/lang/String;)V");

    if (javaConstructor == NULL) {
        LOGP("Find method Failed.\n");
    } else {
        LOGP("Found method.\n");
    }

    jobject pyErrorObject = env->NewObject(javaGlobalClass, javaConstructor, true, env->NewStringUTF("Sample error body"));
    return pyErrorObject;
}

使用 确定方法的签名。另外,看看这里javap -s java.your.package.YourClass

如果您遇到类似于以下内容的错误:您的方法签名错误,您正在向其传递错误的参数,或者您没有使用jni对象的全局状态 - 此处有更多内容JNI ERROR (app bug): attempt to use stale Global 0xf2ac01baenv->NewObject()


推荐