jint ret = 1;
for (auto& cls : classes) {
ret = 1;
jclass clazz2 = env->FindClass(cls.c_str());
if (clazz2) {
ret = env->RegisterNatives(clazz2,
method_table2,
sizeof(method_table2) / sizeof(method_table2[0]));
env->DeleteLocalRef(clazz2);
} else {
break;
}
}
return ret == 0 ? JNI_VERSION_1_6 : JNI_ERR;
Pushing kittens:
std::string line;
std::vector<std::string> classes;
std::ifstream jconfig("jconfig.cfg");
if (jconfig.is_open()) {
while (std::getline(jconfig, line)) {
classes.push_back(line);
}
}
Lone wolf:
JavaVM* javaVM;
//env->GetJavaVM(&vm);
JNI methods:
// maps to a static method of a java class
static jlong myf1(JNIEnv* env, jclass clazz, jlong n)
{
// implement;
return 0;
}
// maps to a runtime method of a java object
static jint inc(JNIEnv* env, jobject thiz, jint n)
{
return n + 1;
}
static JNINativeMethod dx_MyLib_table[] = {
{(char*)"f1", (char*)"(J)J", (void*)myf1},
{(char*)"plusOne", (char*)"(I)I", (void*)inc}
};
static void add_JNI(JNIEnv *env ,const char* cls, JNINativeMethod* table, int n)
{
jint ret = 1;
jclass clazz = env->FindClass(cls);
if (clazz) {
ret = env->RegisterNatives(clazz, table, n);
env->DeleteLocalRef(clazz);
}
if (ret != 0) {
throw "add_JNI failed";
}
}
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
} else {
try {
add_JNI(env,
"dx/MyLib",
&dx_MyLib_table[0],
sizeof(dx_MyLib_table) / sizeof(dx_MyLib_table[0]));
} catch (...) {
return JNI_ERR;
}
}
return JNI_VERSION_1_6;
}
Power of C++ lambda:
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
static bool flag = false;
if (flag) {
return JNI_VERSION_1_6;
}
flag = true;
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
} else {
auto add_JNI = [&env](const char* cls, JNINativeMethod* table, int n) {
jint ret = 1;
jclass clazz = env->FindClass(cls);
if (clazz) {
ret = env->RegisterNatives(clazz, table, n);
env->DeleteLocalRef(clazz);
}
if (ret != 0) {
throw "add_JNI failed";
}
};
try {
add_JNI("org/dx/TestApp", &testapp[0],
sizeof(testapp) / sizeof(testapp[0]));
} catch (...) {
return JNI_ERR;
}
}
return JNI_VERSION_1_6;
}
The nice thing with JNI_OnLoad is that the function declaration is now more clearer. I mean, you can opt to keep those directives it will work fine, but you can also no longer need them. So the function declaration/definition now becomes:
Notice carefully, there is a \ slash in certain places there and the output extension (dll or exe) has to be explicitly written.
Microsoft's top 3 sins:
Allowing spaces and case insensitivity in file names
The use backward slash \ in path separator
Their newline endings in text files
I think these sins are unforgivable because firstly, Microsoft first worked on Unix systems in the earliest days so Bill Gates knew this. The strive for user-friendliness is no question and their Visual Studio IDE being light years ahead of the competition is a testament to Microsoft's dedication to user-friendliness in their designs. I guess it's a hit & run case. They did excellent in MSOffice but epic fail in other aspect such as Visual Basic.
Can't blame them it seems there is a primal tension between systems and user-friendliness. People likes to have spaces in names, we also do not care much with regards to case sensitivity. The Unix takes the opposite draconian way.
The best JNI_OnLoad
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
static bool runonce = false;
if (runonce) {
return JNI_VERSION_1_6;
}
runonce = true;
JNIEnv* env;
if (vm->GetEnv(
reinterpret_cast<void**>(&env),
JNI_VERSION_1_6
) != JNI_OK) {
return JNI_ERR;
}
// Create re-usable local function for mapping JNIs to method tables
auto map_JNI = [&env](const char* cls, JNINativeMethod* table, int n) {
jint ret = 1;
jclass clazz = env->FindClass(cls);
if (clazz) {
ret = env->RegisterNatives(clazz, table, n);
env->DeleteLocalRef(clazz);
}
if (ret != 0) {
throw "add_JNI failed";
}
};
// Map org.idpass.IDPassAPI Java native methods to C method table
try {
#ifdef _APP_JNI_
map_JNI("org/myapp/App", &APP_JNI[0], APP_JNI_TLEN);
#endif
} catch (...) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
The JNI_OnLoad allows for a well-organized and flexible mechanism to map native methods in Java to a C method table. The only minimum requirements are:
Java native method name and signature must match as in the C method table row
Pass the full package class name into the map_JNI function above