2016-10-12 50 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