This C++17 header-only library provides handy wrapper classes for JNI objects.
The library provides:
- Safe way to manage
jobject
lifetimes. - Safe way to get
JniEnv
pointer that is associated with current thread. - Simpler method invocation with automatic signature generation for simple JNI types.
- Simpler field getters and setters with automatic signature generation for simple JNI types.
- Java exception marshalling.
- A more advanced class name to signature generation using constexpr character strings as non-type template parameters
Simple usage:
JObject strObj = JVM::getEnv().getClass("java/lang/String").createObject();
const auto strLen = strObj.invokeMethod<jlong>("length");
More advanced use case:
package my.package;
class MyClass
{
private Number x = 0;
MyClass() {
}
MyClass(Number n) {
x = n;
}
Number getX() {
return x;
}
void setX(Number n) {
x = n;
}
}
constexpr const char java_lang_Number[] = "java.lang.Number";
constexpr const char my_package_MyClass[] = "my.package.MyClass";
JClassS<java_lang_Number> ncls;
JObjectS<java_lang_Number> n = ncls.createObjectS();
JString str = n.invokeMethod<JString>("toString");
JClassS<my_package_MyClass> mycls;
JObjectS<my_package_MyClass> my = mycls.createObjectS(n);
JObjectS<java_lang_Number> n2 = my.invokeMethod<JObjectS<java_lang_Number>>("getX");
my.invokeMethod<JObjectS<java_lang_Number>>("setX", n);
my.invokeMethod<JObjectS<java_lang_Number>>("setX", n2);
Register native method:
void myNativeMethod(JNIEnv* /*env*/, jobject thiz, jlong val)
{
JObject obj(thiz);
const auto fieldVal = obj.getField<jlong>("someLongField");
obj.invokeMethod<void>("callBack", val + fieldVal);
}
void registerMethod()
{
JVM::getEnv().getClass("my/java/Class").registerNativeMethod<void>("myNativeMethod", &myNativeMethod);
}
Jni_BuildTests
- build unittestsJni_AutoInit
- automatically initialize JVM static object
Java virtual machine pointer wrapper.
Methods:
static void init(JavaVM*)
- initialize JVM static object manually. This must be called before any other class can be used! This is automatically called whenJni_AutoInit
build option is enabled.static JEnv getEnv()
- get JNI environment wrapper for current thread.
JNI environment wrapper.
Constructors:
JEnv(JNIEnv*)
- the wrapper constructor
Methods:
JClass getClass(const char* classPath)
- get a JClass wrapper object for a class path (i.e.java/lang/String
).JClass getObjectClass(jobject)
- get a JClass wrapper object for a JNI object.
Internal JNI helper methods (you might not need to use them):
JNIEnv* operator->()
- access JNIEnv pointer
Java class object wrapper.
The wrapper manages the wrapped jobject lifetime and deletes reference when wrapper get's destroyed.
Constructors:
JClass(const jclass&)
- the wrapper constructor
Methods:
std::string getClassPath()
- get the class path of current JClass object (handy for signature generation)void registerNativeMethodSign<TReturn, TArgs...>(const char* name, const char* signature, TReturn(*fn)(JNIEnv*, jobject, TArgs...))
- register a native method that matches the name and signaturevoid registerNativeMethod<TReturn, TArgs...>(const char* name, TReturn(*fn)(JNIEnv*, jobject, TArgs...))
- register a native method that matches the name (the signature is automatically generated at compile time from TReturn and TArgs... types)JObject createObjectSign<TArgs...>(const char* signature, const TArgs&... args)
- construct a new object by calling a constructor that matches the signatureJObject createObject<TArgs...>(const TArgs&... args)
- construct a new object (the signature is automatically generated at compile time from TArgs... types)TReturn invokeMethodSign<TReturn, TArgs...>(const char* name, const char* signature, const TArgs&... args)
- invoke static method by name and signatureTReturn invokeMethod<TReturn, TArgs...>(const char* name, const TArgs&... args)
- invoke static method by name (the signature is automatically generated at compile time from TReturn and TArgs... types)T getFieldSign<T>(const char* name, const char* signature)
- get static field value by name and signatureT getField<T>(const char* name)
- get static field value by name (the signature is automatically generated at compile time from T type)void setFieldSign<T>(const char* name, const char* signature, const T& value)
- set static field value by name and signaturevoid setField<T>(const char* name, const T& value)
- set static field value by name (the signature is automatically generated at compile time from T type)
Internal JNI helper methods (you might not need to use them):
operator jclass()
- accessjclass
objectjmethodID getStaticMethodIdSign(const char* name, const char* signature)
- get a static method ID from name and signature stringsjmethodID getStaticMethodId<TReturn, TArgs...>(const char* name)
- get a static method ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)jmethodID getMethodIdSign(const char* name, const char* signature)
- get an instance method ID from name and signature stringsjmethodID getMethodId<TReturn, TArgs...>(const char* name)
- get an instance method ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)jmethodID getStaticFieldIdSign(const char* name, const char* signature)
- get a static field ID from name and signature stringsjmethodID getStaticFieldId<TReturn, TArgs...>(const char* name)
- get a static field ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)jmethodID getFieldIdSign(const char* name, const char* signature)
- get an instance field ID from name and signature stringsjmethodID getFieldId(const char* name)
- get an instance field ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)
Template jclass wrapepr with Java class name passed via non-type template parameter (constexpr const char ClassName[]
). This class extends JClass so it has all the same methods as above with additional methods listed bellow.
Constructors:
JClassS()
- create new jclass wrapperJClassS(const jclass&)
- wrap around an existing JNI object
Methods:
JObjectS<ClassName> createObjectS(const TArgs&... args)
- create new object and returnJObjectS<ClassName>
JClassS<ClassName> createGlobalRefS()
- create new global reference to jclass object and wrap it inJClassS<ClassName>
JClassS<ClassName> createWeakGlobalRefS()
- create new weak global reference to jclass object and wrap it inJClassS<ClassName>
static constexpr const char* getClassName()
- get class name passed via non-type template parameter
Java object instance wrapper.
The wrapper manages the wrapped jobject lifetime and deletes reference when wrapper get's destroyed.
Constructors:
JObject()
- construct an empty JNI objectJObject(const jobject&)
- the wrapper constructor
Methods:
TReturn invokeMethodSign<TReturn, TArgs...>(const char* name, const char* signature, const TArgs&... args)
- invoke instance method by name and signatureTReturn invokeMethod<TReturn, TArgs...>(const char* name, const TArgs&... args)
- invoke instance method by name (the signature is automatically generated at compile time from TReturn and TArgs... types)T getFieldSign<T>(const char* name, const char* signature)
- get instance field value by name and signatureT getField<T>(const char* name)
- get instance field value by name (the signature is automatically generated at compile time from T type)void setFieldSign<T>(const char* name, const char* signature, const T& value)
- set instance field value by name and signaturevoid setField<T>(const char* name, const T& value)
- set instance field value by name (the signature is automatically generated at compile time from T type)
Internal JNI helper methods (you might not need to use them):
operator jobject()
- accessjobject
objectjmethodID getMethodIdSign(const char* name, const char* signature)
- get an instance method ID from name and signature stringsjmethodID getMethodId<TReturn, TArgs...>(const char* name)
- get an instance method ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)jmethodID getFieldIdSign(const char* name, const char* signature)
- get an instance field ID from name and signature stringsjmethodID getFieldId(const char* name)
- get an instance field ID from name (the signature is automatically generated at compile time from TReturn and TArgs... types)
Template jobject wrapepr with Java class name passed via non-type template parameter (constexpr const char ClassName[]
). This class extends JObject so it has all the same methods as above, with additional methods listed bellow.
Constructors:
JObjectS()
- create empty JNI object wrapperJObjectS(const jobject&)
- wrap around an existing JNI object
Methods:
JObjectS<ClassName> createGlobalRefS()
- create new global reference to jclass object and wrap it inJObjectS<ClassName>
JObjectS<ClassName> createWeakGlobalRefS()
- create new weak global reference to jclass object and wrap it inJObjectS<ClassName>
static constexpr const char* getClassName()
- get class name passed via non-type template parameter
Global reference container - use this class to take global reference ownership of the Java object.
Constructors:
JGlobalRef(jobject)
Methods:
JObject* operator->()
- access the underlyingJObject
Internal JNI helper methods (you might not need to use them):
operator jobject()
- accessjobject
object
Wrapper for jstring
object that gives RAII safe approach to convert it into std::string
and back.
Constructors:
JString(const jstring&)
- the wrapper constructor
Methods:
static JString createFrom(JEnv, const std::string&)
- construct a newJString
fromstd::string
operator std::string()
- construct newstd::string
fromjstring
operator jstring()
- access internaljstring
object
Wrapper for j*Array
objects that gives RAII safe approach to convert it into std::vector<T>
and back.
Predefined types:
JBooleanArray
- convertsjbooleanArray
tostd::vector<bool>
and backJByteArray
- convertsjbyteArray
tostd::vector<std::int8_t>
and backJCharArray
- convertsjcharArray
tostd::vector<char>
and backJShortArray
- convertsjshortArray
tostd::vector<std::int16_t>
and backJIntArray
- convertsjintArray
tostd::vector<std::int32_t>
and backJLongArray
- convertsjlongArray
tostd::vector<std::int64_t>
and backJFloatArray
- convertsjfloatArray
tostd::vector<float>
and backJDoubleArray
- convertsjdoubleArray
tostd::vector<double>
and back
Methods:
Constructors:
JArray<TCpp, TJArray, TJArrayElement>(TJArray)
- the wrapper constructor (wrapTJArray
- i.e.j*Array
object)
Methods:
static TJni createFrom(JEnv, const std::vector<TCpp>&)
- construct a newTJni
fromstd::vector<TCpp>
operator std::vector<TCpp>()
- construct newstd::vecotr<TCpp>
fromTJni
operator TJni()
- access internalTJni
object
JNI object arrays are handled differently from other array types so it has it's own specialization of the array wrapper.
Constructors:
JObjectArray(const jobjectArray&)
Methods:
operator std::vector<JObject>()
- construct newstd::vecotr<JObject>
fromjobjectArray
(wraps each element inJObject
class)operator jobjectArray()
- access internaljobjectArray
objectJObject operator[](int index)
- access each element of the array directlystatic JObjectArray createFrom(const std::vector<JObject>& cppArray, const JClass& elementClass)
- create a newjobjectArray
wrapper fromstd::vector
ofJObject
elementsstatic JObjectArray createNew(std::size_t initSize, const JObject& initObject, const JClass& elementClass)
- create a newjobjectArray
wrapper
Template jobject wrapepr with Java class name passed via non-type template parameter (constexpr const char ClassName[]
). This class extends JObject so it has all the same methods as above, with additional methods listed bellow.
Constructors:
JObjectArrayS(const jobjectArray&)
Methods:
operator std::vector<JObjectS<ElementClassName>>()
- construct newstd::vecotr<JObjectS<ElementClassName>>
fromjobjectArray
(wraps each element inJObjectS
class)JObjectS<ElementClassName> operator[](int index)
- access each element of the array directlystatic JObjectArrayS<ElementClassName> createFromS(const std::vector<JObjectS<ClassName>>& vector)
- create a newjobjectArray
wrapper fromstd::vector
ofJObjectS
elementsstatic JObjectArrayS<ElementClassName> createNewS(std::size_t initSize, const JObjectS<ClassName>& initObject)
- create a newjobjectArray
wrapperstatic constexpr const char* getClassName()
- get class name passed via non-type template parameter
- Global references for arrays (maybe drop JGlobalRef)
- Exception marshalling from C++ to Java
- Introduce new abstraction with just JNI::Object which would act like a wrapper around both JObjectS and JClassS and act like dirrect mirror to Java class with option to register native methods, call static methods via
static invoke
method and instance methods via instanceinvoke
method and be constructable via C++ constructor.
// it would be nice to have something like this:
constexpr const char java_lang_StringBuffer[] = "java.lang.StringBuffer";
constexpr const char java_lang_Thread[] = "java.lang.Thread";
constexpr const char my_package_MyClass[] = "my.package.MyClass";
// Java equivalents:
// Construct new JNI object
JNI::Object<java_lang_StringBuffer> buffer { 1024 }; // StringBuffer buffer = new StringBuffer(1024);
// Invoke instance method
auto c = buffer.invoke<char>("charAt", 123); // char c = buffer.charAt(123);
// Invoke static method
auto currentThread = JNI::Object<java_lang_Thread>::invoke<JNI::Object<java_lang_Thread>>("currentThread");
// Thread currentThread = Thread.currentThread();
// Get static field and immediatelly cast it to STL type
auto x = JNI::Object<my_package_MyClass>::getField<std::string>("staticStringField");
// Set static field from STL/C++ type
JNI::Object<my_package_MyClass>::setField("staticStringField", "some string");
JNI::Object<my_package_MyClass> my;
// Get instance field
auto y = my.getField<std::string>("instanceStringField");
// Set instance field
my.setField("instanceStringField", "my string");