How can I get the values of a jobject in C?
I use JNI
and call a java function in C. The parameter is a jobject and it should look like that: {"John", "Ganso", 5}
.
Now I want to get the values from that object but I dont know how. Do you have any suggestions how to solve that?
My struct in C looks like my class in java.
My code looks like that:
JNIEXPORT void JNICALL
Java_model_JNIResultSet_printToFile(JNIEnv *env, jobject obj,
jobject o) {
// How can I get values of jobject o?
}
jobject thiz means the this in java class. Sometimes if you create a static native method like this. void Java_MyClass_method1 (JNIEnv *, jclass); jclass means the class itself. Follow this answer to receive notifications.
The jclass instance is your object on which a method will be invoked; you'll need to look up the getName method ID on the Class class, then invoke it on the jclass instance using CallObjectMethod to obtain a jstring result. So in short yes, you just call the getName function and look at the jstring result.
A JNI global reference is a reference from "native" code to a Java object managed by the Java garbage collector. Its purpose is to prevent collection of an object that is still in use by native code, but doesn't appear to have any live references in the Java code. A JFrame is a java. awt.
JNIEnv – a structure containing methods that we can use our native code to access Java elements. JavaVM – a structure that lets us manipulate a running JVM (or even start a new one) adding threads to it, destroying it, etc…
1. Introduction At times, it is necessary to use native (non-Java) codes (e.g., C/C++) to overcome the memory management and performance constraints in Java. Java supports native codes via the Java Native Interface (JNI). JNI is difficult, as it involves two languages and runtimes.
JNIEnv*: reference to JNI environment, which lets you access all the JNI functions. jobject: reference to " this " Java object. We are not using these arguments in this hello-world example, but will be using them later.
As the return value from calling a JNI function A valid JNI global reference must be obtained from another valid JNI reference (global or local) by calling NewGlobalRef or NewWeakGlobalRef. The null value reference is always valid, and can be used in place of any JNI reference (global or local).
Whether you're writing native methods or embedding a JVM in your C program, you really ought to read the JNI documentation. It contains quite a bit of information you will need to know, including details of the JNI functions for accessing the fields of a Java object. Obtain its field ID via GetFieldID ().
/* 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
You can find it easier to checkout the project and compile it:
https://github.com/mkowsiak/jnicookbook
Whether you're writing native methods or embedding a JVM in your C program, you really ought to read the JNI documentation. It contains quite a bit of information you will need to know, including details of the JNI functions for accessing the fields of a Java object.
In brief, to get the value of a field, you
Obtain its field ID via GetFieldID()
. This will require that you also get (or already have) a jclass
object representing the class to which the field belongs; you might obtain that via GetObjectClass()
or FindClass()
.
Obtain the field's value with the one of the GetXXXField()
methods for which XXX
is appropriate to the field's declared type. For Java String
s, that would be GetObjectField()
; for Java int
s it would be GetIntField()
.
If you want to look at the details of the strings, you will need to also use some of the String manipulation functions, such as GetStringUTFChars()
and GetStringUTFLength()
. And do not overlook the important distinction between those functions, which operate in terms of modified UTF-8, and the analogous functions that operate in terms of "Unicode characters" (which really means UTF-16).
I agree with John Bollinger. Here is an example based on another [question]:JNI. How to get jstring from jobject and convert it to char*
In your case if the class in java is Person and the fields are firstName, lastName, and age then you might try the following code:
// 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);
Now you can use that data to fill your struct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With