如何使用JNI从C中的jobject获取值?

时间:2016-10-12 17:12:05

标签: c object java-native-interface

如何在C中获取作业的值? 我使用$(function() { $('input[type=checkbox]').change(function() { if (this.checked) { $(this).closest('tr').find('input[type=text]').prop('disabled', true); } else { $(this).closest('tr').find('input[type=text]').prop('disabled', false); } }); }); 并在C中调用java函数。参数是一个jobject,它看起来应该是这样的:JNI
现在我想从该对象获取值,但我不知道如何。你对如何解决这个问题有什么建议吗? 我在C中的结构看起来像是我在java中的类。

我的代码看起来像这样:

{"John", "Ganso", 5}

3 个答案:

答案 0 :(得分:5)

/* PassObject.java */
package recipeNo020;

public class PassObject {

    /* This is the native method we want to call */
    public static native void displayObject(Object obj);

    /* Inside static block we will load shared library */
    static {
            System.loadLibrary("PassObject");
    }

    public static void main(String[] args) {
    /* This message will help you determine whether
        LD_LIBRARY_PATH is correctly set
    */
    System.out.println("library: "
        + System.getProperty("java.library.path"));

    /* Create object to pass */
    CustomClass cc = new CustomClass();
    cc.iVal = 1;
    cc.dVal = 1.1;
    cc.cVal = 'a';
    cc.bVal = true;
    cc.sVal = "Hello from the CustomClass";
    cc.oVal = new OtherClass();
    cc.oVal.sVal = "Hello from the OtherClass";

    /* Call to shared library */
        PassObject.displayObject(cc);
  }
}

/* CustomClass.java */
package recipeNo020;

public class CustomClass {
    public int iVal;
    public double dVal;
    public char cVal;
    public boolean bVal;
    public OtherClass oVal;
    public String sVal;
}

/* OtherClass.java */
package recipeNo020;

public class OtherClass {
    public String sVal;
}

/* recipeNo020_PassObject.c */

#include <stdio.h>
#include "jni.h"
#include "recipeNo020_PassObject.h"

JNIEXPORT void JNICALL Java_recipeNo020_PassObject_displayObject
  (JNIEnv *env, jclass obj, jobject objarg) {

    /* Get objarg's class - objarg is the one we pass from
       Java */
    jclass cls = (*env)->GetObjectClass(env, objarg);

    /* For accessing primitive types from class use
           following field descriptors

           +---+---------+
           | Z | boolean |
           | B | byte    |
           | C | char    |
           | S | short   |
           | I | int     |
           | J | long    |
           | F | float   |
           | D | double  |
           +-------------+
    */

    /* Get int field

       Take a look here, we are passing char* with
           field descriptor - e.g. "I" => int
        */
    jfieldID fidInt = (*env)->GetFieldID(env, cls, "iVal", "I");
    jint iVal = (*env)->GetIntField(env, objarg, fidInt);
    printf("iVal: %d\n", iVal);

    /* Get double field */
    jfieldID fidDouble = (*env)->GetFieldID(env, cls, "dVal", "D");
    jdouble dVal = (*env)->GetIntField(env, objarg, fidDouble);
    printf("dVal: %f\n", dVal);

    /* Get boolean field */
    jfieldID fidBoolean = (*env)->GetFieldID(env, cls, "bVal", "Z");
    jboolean bVal = (*env)->GetIntField(env, objarg, fidBoolean);
    printf("bVal: %d\n", bVal);

    /* Get character field */
    jfieldID fidChar = (*env)->GetFieldID(env, cls, "cVal", "C");
    jboolean cVal = (*env)->GetIntField(env, objarg, fidChar);
    printf("cVal: %c\n", cVal);

    /* Get String field */
    jfieldID fidString = (*env)->GetFieldID(env, cls, "sVal", "Ljava/lang/String;");
    jobject sVal = (*env)->GetObjectField(env, objarg, fidString);

    // we have to get string bytes into C string
    const char *c_str;
    c_str = (*env)->GetStringUTFChars(env, sVal, NULL);
    if(c_str == NULL) {
            return;
    }

    printf("sVal: %s\n", c_str);

    // after using it, remember to release the memory
    (*env)->ReleaseStringUTFChars(env, sVal, c_str);

    /* Get OtherClass */
    jfieldID fidOtherClass = (*env)->GetFieldID(env, cls, "oVal", "LrecipeNo020/OtherClass;");
    jobject oVal = (*env)->GetObjectField(env, objarg, fidOtherClass);

    jclass clsOtherClass = (*env)->GetObjectClass(env, oVal);

    /* Once we have OtherClass class and OtherClass object
       we can access OtherClass'es components
    */

    /* Get String field from OtherClass */
    jfieldID fidStringOtherClass = (*env)->GetFieldID(env, clsOtherClass, "sVal", "Ljava/lang/String;");
    jobject sValOtherClass = (*env)->GetObjectField(env, oVal, fidStringOtherClass);

    // we have to get string bytes into C string
    const char *c_str_oc;
    c_str_oc = (*env)->GetStringUTFChars(env, sValOtherClass, NULL);
    if(c_str_oc == NULL) {
        return;
    }

    printf("OtherClass.sVal: %s\n", c_str_oc);

    // after using it, remember to release the memory
    (*env)->ReleaseStringUTFChars(env, sValOtherClass, c_str_oc);
}

/* Make file */

include ../Makefile.common

all: compilejava compilec

compilec:
    cc -g -shared -fpic -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(ARCH) c/recipeNo020_PassObject.c -o lib/libPassObject.$(EXT)


compilejava:
    $(JAVA_HOME)/bin/javac -cp target -d target java/recipeNo020/OtherClass.java
    $(JAVA_HOME)/bin/javac -cp target -d target java/recipeNo020/CustomClass.java
    $(JAVA_HOME)/bin/javac -cp target -d target java/recipeNo020/PassObject.java
    $(JAVA_HOME)/bin/javah -jni -d c -cp target recipeNo020.PassObject

test:
    $(JAVA_HOME)/bin/java -Djava.library.path=$(LD_LIBRARY_PATH):./lib -cp target recipeNo020.PassObject

.PHONY: clean
clean:
    -rm -rfv target/*
    -rm c/recipeNo020_PassObject.h
    -rm -rfv lib/*

/* directory structure */
.
├── Makefile
├── c
│   └── recipeNo020_PassObject.c
├── java
│   └── recipeNo020
│       ├── CustomClass.java
│       ├── OtherClass.java
│       └── PassObject.java
├── lib
└── target

/* execution */
make
make test

您可以更轻松地签出项目并进行编译:

https://github.com/mkowsiak/jnicookbook

答案 1 :(得分:2)

无论您是编写本机方法还是在C程序中嵌入JVM,您都应该阅读the JNI documentation。它包含了您需要了解的大量信息,包括the JNI functions for accessing the fields of a Java object的详细信息。

简而言之,要获得字段的值,

  1. 通过db.getCollection('mycollection').eval(function construct(){ var res = db.getCollection('mycollection').find(query); var explain = res.explain()['server']; return {'server':explain,'result':res.toArray()}; })() 获取其字段ID。这将要求您获得(或已经拥有)表示该字段所属类的{ "server" : "myservernode.mydomain:27017", "result" : [ // your query results ] } 对象;您可以通过GetFieldID()jclass

  2. 获取
  3. 使用GetObjectClass()方法之一获取字段的值,FindClass()适合字段的声明类型。对于Java GetXXXField(),那将是XXX;对于Java String,它将是GetObjectField()

  4. 如果您想查看字符串的详细信息,还需要使用String manipulation functions中的一些内容,例如intGetIntField()。并且不要忽视那些以修改后的UTF-8运行的功能与以“Unicode字符”(实际上意味着UTF-16)运行的类似功能之间的重要区别。

答案 2 :(得分:0)

我同意John Bollinger的观点。 以下是基于另一个[问题]的示例:JNI. How to get jstring from jobject and convert it to char*

在您的情况下,如果java中的类是Person,并且字段是firstName,lastName和age,那么您可以尝试以下代码:

    // How can I get values of jobject o?
    jclass personClass = (*env)->GetObjectClass(env, o);
    jfieldID firstNameId = (*env)->GetFieldID(env,personClass,"firstName","S");
    jstring firstNameString = (jstring)(*env)->GetObjectField(env, o, firstNameId);
    jfieldID lastNameId = (*env)->GetFieldID(env,personClass,"lastName","S");
    jstring lastNameString = (jstring)(*env)->GetObjectField(env, o, lastNameId);
    jfieldID ageId = (*env)->GetFieldID(env,personClass,"age","I");
    jint age = (*env)->GetIntField(env,o,ageId);

现在您可以使用该数据填充您的结构。