简体   繁体   English

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

[英]Use JNI to Create, Populate and Return a Java Class Instance

I'm trying to use a JNI function to create a Java class and set some properties of that class using the DeviceId.java constructor method. 我正在尝试使用JNI函数创建Java类,并使用DeviceId.java构造函数方法设置该类的一些属性。 I'm able to get the constructor method using the GetMethodID, but how would I create a new instance of Device.java and then set the properties (setId and setCache). 我能够使用GetMethodID获取构造函数方法,但是如何创建Device.java的新实例然后设置属性(setId和setCache)。 The goal is to return a fully populated instance of Device.java Object to the caller. 目标是将完全填充的Device.java对象实例返回给调用者。 Any ideas? 有任何想法吗?

JNI Function: 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 Class: 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;
    }   
}

When you called GetMethodID , you provided the signature for the two-arg constructor. 当您调用GetMethodID ,您为two-arg构造函数提供了签名。 Thus, you just need to pass your jstring and a jbytearray when you call NewObject - for example: 因此,您只需要在调用NewObject时传递jstringjbytearray - 例如:

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

You don't need to call the setId and setCache methods unless you decide to call the 0-arg constructor - and that just complicates your code since you'll have to call GetMethodID for those and call them. 你不需要调用setIdsetCache方法,除非你决定调用0-arg构造函数 - GetMethodID会使你的代码复杂化,因为你必须为那些调用GetMethodID并调用它们。 Simpler to continue down the route you're on. 更容易继续沿着您所在的路线行进。

I wanted to return a custom Java object from JNI's cpp code back to Java. 我想将一个自定义 Java对象从JNI的cpp代码返回给Java。 The solution is to return a jobject from cpp function and use our custom Java object in native method declaration. 解决方案是从cpp函数返回一个jobject ,并在本机方法声明中使用我们的自定义Java对象。

public class PyError {

    public String message;

    public boolean occurred;

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

and method declaration in Java: 和Java中的方法声明:

native PyError nativePythonErrorOccurred();

on the cpp side: 在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;
}

Determine the signature of the method using javap -s java.your.package.YourClass . 使用javap -s java.your.package.YourClass确定方法的签名。 Also, have a look here . 另外,看看这里

If you encounter error similar to: JNI ERROR (app bug): attempt to use stale Global 0xf2ac01ba your method signature is wrong, you're passing wrong arguments to env->NewObject() or you're not using global state of jni objects - more here . 如果您遇到类似于以下JNI ERROR (app bug): attempt to use stale Global 0xf2ac01baJNI ERROR (app bug): attempt to use stale Global 0xf2ac01ba您的方法签名是错误的,您将错误的参数传递给env->NewObject()或者您没有使用全局jni对象状态- 更多在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM