2016-10-12 23 views
3

我怎样才能得到一个工作对象在C中的值?
我使用JNI并在C中调用java函数。参数是一个jobject,它应该看起来像这样:{"John", "Ganso", 5}
现在我想从该对象获取值,但我不知道如何。你有什么建议如何解决?
我在C中的结构看起来像我在java中的类。如何使用JNI从C中的jobject获取值?

我的代码看起来像这样:

JNIEXPORT void JNICALL 
Java_model_JNIResultSet_printToFile(JNIEnv *env, jobject obj, 
    jobject o) { 

// How can I get values of jobject o? 
} 

回答

1

无论你写的本地方法或者在你的C程序中嵌入一个JVM,你真的应该阅读the JNI documentation。它包含了相当多的信息,您需要知道,其中包括the JNI functions for accessing the fields of a Java object的详细信息。

总之,要获得字段的值,你

  1. 通过GetFieldID()获得其ID字段。这将要求您还获得(或已经拥有)表示该字段所属类别的对象:jclass。你可能通过GetObjectClass()FindClass()获得。

  2. 获取该字段的值,其中XXX适用于该字段的声明类型的GetXXXField()方法之一。对于Java String s,那将是GetObjectField();对于Java int s它将是GetIntField()

如果你想看看字符串的细节,你将也需要使用一些String manipulation functions,如GetStringUTFChars()GetStringUTFLength()。不要忽视这些函数之间的重要区别,这些函数根据修改后的UTF-8进行操作,以及根据“Unicode字符”(实际上意味着UTF-16)进行操作的类似函数。

+0

GetFieldId()预计,字段名和字段的数据类型,如果我们不知道是什么这两件事是什么?有没有办法让他们? – kumarD

+0

@kumarD,你可以使用Java的反射API('java.lang.Class','java.lang.reflect.Field'等),从Java端更容易,但如果需要,可以从本地端获取信息关于一个班级的领域。 JNI具有[可以在反射API对象和JNI之间桥接的函数](http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#reflection_support)。但是如果你发现自己想要这样做,那么你应该有一个很好的长期思考。如果这并不能消除你的想法,那么头上的一个屁股可能会有所帮助。 –

+0

其实我想捕捉应用程序的状态,如方法变量值,类变量值等,当发生异常时,这是唯一可以实现的方法吗? – kumarD

0

我同意约翰布林杰。 这是基于另一个[问题]一个例子:JNI. How to get jstring from jobject and convert it to char*

在如果在Java类是人事和领域你的情况是名字,姓氏和年龄,那么你可以尝试下面的代码:

// 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); 

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

1
/* 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

+0

非常感谢:) –

+1

.oOo。 np;)与JNI玩得开心! .oOo。 – mko