Skip to content

Instantly share code, notes, and snippets.

@grdima grdima/JniClass.h
Created May 18, 2018

Embed
What would you like to do?
Metersnap JNI Wrapper
#ifndef METERSNAP_ANDROID_JNICLASS_H
#define METERSNAP_ANDROID_JNICLASS_H
#include <jni.h>
#include <string>
#include <sstream>
class JniClass;
class JniObject;
namespace impl{
template <typename T>
std::string GetTypeName();
typedef unsigned char jboolean; /* unsigned 8 bits */
typedef signed char jbyte; /* signed 8 bits */
typedef unsigned short jchar; /* unsigned 16 bits */
typedef short jshort; /* signed 16 bits */
typedef int jint; /* signed 32 bits */
typedef long long jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
#define REGISTER_TYPE(type, name) template<> std::string GetTypeName<type>() { return name; }
REGISTER_TYPE(jboolean, "Z");
REGISTER_TYPE(jbyte , "B");
REGISTER_TYPE(jchar , "C");
REGISTER_TYPE(jshort , "S");
REGISTER_TYPE(jint , "I");
REGISTER_TYPE(jlong , "J");
REGISTER_TYPE(jfloat , "F");
REGISTER_TYPE(jdouble , "D");
REGISTER_TYPE(void , "V");
REGISTER_TYPE(const char *, "Ljava/lang/String;");
#undef REGISTER_TYPE
class JniHolder{
jvalue m_val;
class Holder{
JNIEnv *m_env;
jobject m_obj;
public:
Holder(JNIEnv *env = nullptr, jobject obj = nullptr):
m_env(env), m_obj(obj){
}
~Holder(){
}
jobject obj() const {
return m_obj;
}
} m_holder;
public:
#define CONSTRUCTOR(type, field) explicit JniHolder(JNIEnv *env, type val) : m_val(), m_holder() { field = val; }
CONSTRUCTOR(jboolean, m_val.z);
CONSTRUCTOR(jbyte , m_val.b);
CONSTRUCTOR(jchar , m_val.c);
CONSTRUCTOR(jshort , m_val.s);
CONSTRUCTOR(jint , m_val.i);
CONSTRUCTOR(jlong , m_val.j);
CONSTRUCTOR(jfloat , m_val.f);
CONSTRUCTOR(jdouble , m_val.d);
#undef CONSTRUCTOR
explicit JniHolder(JNIEnv *env, const std::string &val) : m_val(), m_holder(env, env->NewStringUTF(val.c_str())) { m_val.l = m_holder.obj(); }
explicit JniHolder(JNIEnv *env, jobject obj) : m_val(), m_holder(env, obj) { m_val.l = m_holder.obj(); }
const jvalue &value() const {
return m_val;
}
};
template <typename Ret>
struct CallStaticMethodImp;
template <typename Ret>
struct CallInstanceMethodImp;
#define STATIC_METHOD_IMP(type, _jname) \
template <>\
struct CallStaticMethodImp<type>{\
static type CallMethod(JNIEnv *env, jclass clazz, jmethodID method, size_t args_size, jvalue *values){\
if(args_size != 0)\
return env->CallStatic##_jname##MethodA(clazz, method, values);\
return env->CallStatic##_jname##Method(clazz, method);\
}\
};\
template <>\
struct CallInstanceMethodImp<type>{\
static type CallMethod(JNIEnv *env, jobject object, jmethodID method, size_t args_size, jvalue *values){\
if(args_size != 0)\
return env->Call##_jname##MethodA(object, method, values);\
return env->Call##_jname##Method(object, method);\
}\
};
STATIC_METHOD_IMP(jboolean, Boolean);
STATIC_METHOD_IMP(jbyte , Byte);
STATIC_METHOD_IMP(jchar , Char);
STATIC_METHOD_IMP(jshort , Short);
STATIC_METHOD_IMP(jint , Int);
STATIC_METHOD_IMP(jlong , Long);
STATIC_METHOD_IMP(jfloat , Float);
STATIC_METHOD_IMP(jdouble , Double);
STATIC_METHOD_IMP(void , Void);
STATIC_METHOD_IMP(jobject , Object);
#undef STATIC_METHOD_IMP
template <typename... Args>
std::string GenerateTypesString(){
constexpr size_t count = sizeof...(Args);
const std::string typeNames[count] = { GetTypeName<Args>()... };
std::string signature;
signature.append("(");
for(const std::string &s : typeNames)
signature.append(s);
signature.append(")");
return signature;
};
template <typename... Args>
jmethodID GetConstructorId(JNIEnv *env, jclass clazz){
std::string signature = GenerateTypesString<Args...>() + "V";
return env->GetMethodID(clazz, "<init>", signature.c_str());
};
template <typename Ret, typename... Args>
jmethodID GetMethodId(JNIEnv *env, jclass clazz, const std::string &name){
std::string signature = GenerateTypesString<Args...>() + GetTypeName<Ret>();
return env->GetMethodID(clazz, name.c_str(), signature.c_str());
};
template <typename Ret>
struct CallStatic {
template<typename... Args>
static Ret CallStaticMethod(JniClass *clazz, const std::string &name, Args... args);
};
template <>
struct CallStatic<jobject> {
template<typename... Args>
static jobject CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass *returnType, Args... args);
template<typename... Args>
static jobject CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass &returnType, Args... args);
};
template <>
struct CallStatic<JniObject> {
template<typename... Args>
static JniObject CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass *returnType, Args... args);
template<typename... Args>
static JniObject CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass &returnType, Args... args);
};
template <typename Ret>
struct CallInstance{
template <typename... Args>
static Ret CallInstanceMethod(JniObject *obj, const std::string &name, Args... args);
};
template <typename Ret>
struct CallInstanceSignature{
template<typename... Args>
static Ret CallInstanceSignatureMethod(JniObject *obj, const std::string &name, const std::string &signature, Args... args);
};
}
template<typename T>
std::string to_string(T value) {
std::ostringstream os;
os << value;
return os.str();
}
class JniObject {
public:
JniObject(const JniClass *clazz = nullptr, jobject obj = nullptr):
m_object(obj),
m_class(clazz){
}
bool isValid() const{
return m_object != nullptr;
}
jobject object() const {
return m_object;
}
const JniClass *clazz() const {
return m_class;
}
template <typename Ret, typename... Args>
Ret invoke(const std::string &method, Args... args){
return impl::CallInstance<Ret>::CallInstanceMethod(this, method, std::move(args)...);
};
template <typename Ret, typename... Args>
Ret invokeSignature(const std::string &method, const std::string &signature, Args... args){
return impl::CallInstanceSignature<Ret>::CallInstanceSignatureMethod(this, method, signature, std::move(args)...);
};
private:
jobject m_object;
const JniClass * m_class;
};
class JniClass {
public:
JniClass(JNIEnv *env, const std::string &name):
m_env(env),
m_name(name),
m_clazz(env->FindClass(name.c_str())) {
}
template <typename Ret, typename... Args>
Ret invokeStatic(const std::string &method, Args... args){
return impl::CallStatic<Ret>::CallStaticMethod(this, method.c_str(), std::move(args)...);
};
template <typename... Args>
JniObject newInstance(Args... args){
jmethodID constructor = impl::GetConstructorId<Args...>(m_env, m_clazz);
if(constructor != 0) {
constexpr size_t arg_count = sizeof...(Args);
impl::JniHolder holder[arg_count] = { std::move(impl::JniHolder(m_env, args))... };
jvalue values[arg_count] {};
for(int i = 0; i < arg_count; i++){
values[i] = holder[i].value();
}
return { this, m_env->NewObjectA(m_clazz, constructor, values) };
}
return {};
}
JNIEnv *env() const {
return m_env;
}
jclass clazz() const {
return m_clazz;
}
const std::string &name() const {
return m_name;
}
private:
JNIEnv *m_env;
std::string m_name;
jclass m_clazz;
};
namespace impl{
template<typename Ret>
template<typename... Args>
Ret CallStatic<Ret>::CallStaticMethod(JniClass *clazz, const std::string &name, Args... args) {
constexpr size_t arg_count = sizeof...(Args);
JniHolder holder[arg_count] = {std::move(JniHolder(clazz->env(), args))...};
jvalue values[arg_count]{};
for (int i = 0; i < arg_count; i++) {
values[i] = holder[i].value();
}
std::string signature = GenerateTypesString<Args...>() + GetTypeName<Ret>();
jmethodID method = clazz->env()->GetStaticMethodID(clazz->clazz(), name.c_str(),
signature.c_str());
return CallStaticMethodImp<Ret>::CallMethod(clazz->env(), clazz->clazz(), method, arg_count, values);
};
template<>
template<typename... Args>
jobject CallStatic<jobject>::CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass *returnType, Args... args) {
constexpr size_t arg_count = sizeof...(Args);
JniHolder holder[arg_count] = {std::move(JniHolder(clazz->env(), args))...};
jvalue values[arg_count]{};
for (int i = 0; i < arg_count; i++) {
values[i] = holder[i].value();
}
std::string signature = GenerateTypesString<Args...>() + "L" + returnType->name() + ";";
jmethodID method = clazz->env()->GetStaticMethodID(clazz->clazz(), name.c_str(),
signature.c_str());
return CallStaticMethodImp<jobject>::CallMethod(clazz->env(), clazz->clazz(), method, arg_count, values);
};
template<>
template<typename... Args>
jobject CallStatic<jobject>::CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass &returnType, Args... args) {
return CallStaticMethod(clazz, name, &returnType, std::move(args)...);
};
template<>
template<typename... Args>
JniObject CallStatic<JniObject>::CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass *returnType, Args... args) {
constexpr size_t arg_count = sizeof...(Args);
JniHolder holder[arg_count] = {std::move(JniHolder(clazz->env(), args))...};
jvalue values[arg_count]{};
for (int i = 0; i < arg_count; i++) {
values[i] = holder[i].value();
}
std::string signature = GenerateTypesString<Args...>() + "L" + returnType->name() + ";";
jmethodID method = clazz->env()->GetStaticMethodID(clazz->clazz(), name.c_str(), signature.c_str());
return { returnType, CallStaticMethodImp<jobject>::CallMethod(clazz->env(), clazz->clazz(), method, arg_count, values) };
};
template<>
template<typename... Args>
JniObject CallStatic<JniObject>::CallStaticMethod(JniClass *clazz, const std::string &name, const JniClass &returnType, Args... args) {
return CallStaticMethod(clazz, name, &returnType, std::move(args)...);
};
template <typename Ret>
template <typename... Args>
Ret CallInstance<Ret>::CallInstanceMethod(JniObject *obj, const std::string &name, Args... args){
jmethodID method = GetMethodId<Ret, Args...>(obj->clazz()->env(), obj->clazz()->clazz(), name);
constexpr size_t arg_count = sizeof...(Args);
JniHolder holder[arg_count] = {std::move(JniHolder(obj->clazz()->env(), args))...};
jvalue values[arg_count]{};
for (int i = 0; i < arg_count; i++) {
values[i] = holder[i].value();
}
return CallInstanceMethodImp<Ret>::CallMethod(obj->clazz()->env(), obj->object(), method, arg_count, values);
};
template <typename Ret>
template <typename... Args>
Ret CallInstanceSignature<Ret>::CallInstanceSignatureMethod(JniObject *obj, const std::string &name, const std::string &signature, Args... args){
jmethodID method = obj->clazz()->env()->GetMethodID(obj->clazz()->clazz(), name.c_str(), signature.c_str());
constexpr size_t arg_count = sizeof...(Args);
JniHolder holder[arg_count] = {std::move(JniHolder(obj->clazz()->env(), args))...};
jvalue values[arg_count]{};
for (int i = 0; i < arg_count; i++) {
values[i] = holder[i].value();
}
return CallInstanceMethodImp<Ret>::CallMethod(obj->clazz()->env(), obj->object(), method, arg_count, values);
};
}
#endif //METERSNAP_ANDROID_JNICLASS_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.