-
Notifications
You must be signed in to change notification settings - Fork 6
Accessing Methods and Fields
Unless you are doing something very simple with your JNI code you will need to call Java methods and access Java fields from C++. SimpleJNI wraps raw JNI's jmethodID
and jfieldID
and the horrible API that uses them in clean type-safe wrappers. These are called method and field objects. There are slightly different types for instance methods, static methods and constructors. Similarly there are different type for instance and static fields. You declare them using variadic templates as follows
java_method<ReturnType, TypeOfThis, /**param types if any**/>
java_static_method<ReturnType, TypeOfClass, /**param types if any**/>
java_constructor<ReturnType, /**param types if any**/>
java_field<FieldType, TypeOfThis>
java_static_field<FieldType, TypeOfClass>
where TypeOfThis/TypeOfClass are the types of the class exposing the method or field. For Java constructor ReturnType is TypeOfThis so it needs to be specified only once.
Java constructors in SimpleJNI combine the functionality of JNI's NewObject and constructor invocation. These are always used together and there is no reason to introduce potential errors by requiring two distinct calls.
For example consider the following Java class' methods and fields
class Something
{
Something(String arg1, long arg2);
boolean someMethod(String arg1, long arg2);
static boolean someStaticMethod(String arg1, long arg2);
long m_longField;
static long s_longField;
}
These can be accessed in the following way
jJNIEnv * env = ...;
//An instance of the class object for the Something class. See note 1 below
java_class<jSomething> cls = ...;
//Declare and initialize method and field objects. See notes 2 and 3
java_constructor<jSomething, jstring, jlong> ctor(env, cls);
java_method<jboolean, jSomething, jstring, jlong> someMethod(env, cls, "someMethod");
java_static_method<jboolean, jSomething, jstring, jlong> someStaticMethod(env, cls, "someStaticMethod");
java_field<jlong, jSomething> longField(env, cls, "m_longField");
java_static_field<jlong, jSomething> staticLongField(env, cls, "s_longField");
jstring str = ...;
//Now let's call methods and access fields. See note 4
auto obj = ctor(env, str, 42); //See notes 5 and 6
jboolean res = someMethod(env, obj, str, 7);
res = someStaticMethod(env, cls , str, 7);
//non-virtual call. Need to specify class here
res = someMethod.call_non_virtual(env, obj, cls, str, 7);
jlong val = longField.get(env, obj);
longField.set(env, obj, val + 1);
val = staticLongField.get(env, cls);
staticLongField.set(env, cls, val + 1);
Notes:
-
java_class<jSomething>
represent a Java class object. It is required for initialization of any method or field object. See Representing Java Classes for more details. - If you have made a mistake in the method type declaration (say it really returns a
jint
rather thanjboolean
) or mistyped method name the constructor of method/field object will fail with an exception at runtime. - For all methods and fields except Java constructors, the last argument in their constructor calls above is the simple Java name of the method/field. You don't need to know anything about
(Ljava.lang.String;J)B
or whatever the magic incantation is in this case. There is no need to pass any name to thejava_constructor
's constructor. The name of the Java constructor method is pre-defined and fixed so you don't need to know it or care. - If you make a mistake and try to pass wrong arguments to method calls they simply won't compile. Your IDE will also likely be able to auto-complete the calls for you.
- The return type of any SimpleJNI methods that returns Java objects (like the constructor above) is a smart reference. See Smart References for more details.
You can only use "JNI compatible" types in declarations of methods and fields. Those are primitive types like jint
or jlong
, object types like jobject
or jSomething
you declared or jxXXArray
types. Now, things like jint
are actually typedefs which on your particular platform might be the same as int
. You might get away with just typing int
and things will work just fine. However, this will easily break with other types. For example jlong
will very likely be not the same as long
and jboolean
almost certainly not the same as bool
. Plus one day you might want to port your code to another platform and you will discover that there even jint
is not the same as int
.
It is best to get into a habit of always using j-prefixed types in all JNI declarations, whether of Java entities you access or native Java methods you implement.
- Building
-
User's Guide
Declaring Java Types
Accessing Methods and Fields
Representing Java Classes
Implementing Native Methods
Smart References
Error Handling
Obtaining JNIEnv
Initialization
Strings
Arrays
Direct Buffers
Booleans
Sizes -
JniGen Code Generator
Integrating JniGen
Annotations
Processor Options