2016-10-12 6 views
3

Как я могу получить значения задания в C?
Я использую JNI и вызываю функцию java в C. Параметр - это рабочий объект, и он должен выглядеть так: {"John", "Ganso", 5}.
Теперь я хочу получить значения от этого объекта, но я не знаю, как это сделать. Есть ли у вас какие-либо предложения по его решению?
Моя структура в C выглядит как мой класс в java.Как получить значения из jobject в C, используя JNI?

Мой код выглядит следующим образом:

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

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

ответ

1

ли вы писать собственные методы или встраивания JVM в программе C, вы действительно должны читать the JNI documentation. Он содержит довольно много информации, которую вам нужно знать, включая подробную информацию о the JNI functions for accessing the fields of a Java object.

Короче говоря, чтобы получить значение поля, вы

  1. Получить его поле ID с помощью GetFieldID(). Это потребует, чтобы вы также получили (или уже имеете) объект jclass, представляющий класс, к которому принадлежит это поле; вы можете получить это через GetObjectClass() или FindClass().

  2. Получить значение поля с помощью метода GetXXXField(), для которого XXX подходит к типу объявления поля. Для Java String s это будет GetObjectField(); для Java int s было бы GetIntField().

Если вы хотите посмотреть на детали строк, вам нужно будет также использовать некоторые из String manipulation functions, таких как GetStringUTFChars() и GetStringUTFLength(). И не забывайте о важном различии между этими функциями, которые работают с точки зрения модифицированного UTF-8, и аналогичными функциями, которые действуют в терминах «Unicode characters» (что действительно означает UTF-16).

+0

GetFieldID() ожидает, что имя поля и тип данных поля, что, если мы не знаем, что это за две вещи? есть ли способ их получить? – kumarD

+0

@kumarD, вы можете использовать API отражения Java ('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*

В вашем случае, если класс в Яве Люди и поля являются ПгвЬЫатом, LastName, и возраст, то вы можете попробовать следующий код:

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