#include <iostream> |
#include <jni.h> |
#include <stdio.h> |
#include <windows.h> |
#include "HelloJNI.h" |
|
using namespace std; |
|
static jclass intClass; |
|
JNIEXPORT jdouble JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject obj, jint n1, jstring s){ |
//get the jstring |
const char *str = env->GetStringUTFChars(s, 0); |
if (str == NULL) return 0.0; |
cout << "Hello " << str << ", i = " << n1 << endl; |
//printf("Hello %s, i=%d\n", str, n1); |
env->ReleaseStringUTFChars(s, str); |
|
/*string outCppStr; |
cout << "Enter a String: "; |
cin >> outCppStr; |
return env->NewStringUTF(outCppStr.c_str()); |
*/ |
return n1 + 1.0; |
} |
|
JNIEXPORT void JNICALL Java_HelloJNI_showPrimitives |
(JNIEnv * env, jobject obj, jint i, jbyte b, jshort s, jlong l, jfloat f, jdouble d, jchar c, jboolean bo){ |
cout << "Integer:" << i << endl; |
cout << "Byte:" << b << endl; |
cout << "Short:" << s << endl; |
cout << "Long:" << l << endl; |
cout << "Float:" << f << endl; |
cout << "Double:" << d << endl; |
cout << "Char:" << c << endl; |
cout << "Boolean:" << (bo?"true":"false") << endl; |
} |
|
JNIEXPORT jdoubleArray JNICALL Java_HelloJNI_sumArray |
(JNIEnv * env, jobject obj, jintArray arr){ |
double sum = 0.0; |
|
//Convert the incoming JNI jintarray to C's jint[] |
jint *cArray = env->GetIntArrayElements(arr, NULL); |
if (NULL == arr) return NULL; |
jsize length = env->GetArrayLength(arr); |
|
//Perform operations |
for (int i = 0; i < length; i++){ |
sum += cArray[i]; |
} |
|
jdouble average = (jdouble) sum / length; |
|
jdouble arrValues[] = {sum, average}; |
//Release resoruces |
env->ReleaseIntArrayElements(arr, cArray, 0); |
|
//Convert C's array jdouble[] to JNI jdoublearray |
jdoubleArray outArray = env->NewDoubleArray(2); //allocate |
if (NULL == outArray) return NULL; |
env->SetDoubleArrayRegion(outArray, 0, 2, arrValues); //copy portion (from start to length) |
|
cout << "Length: " << length << endl; |
return outArray; |
} |
|
|
//Modify variable instance |
JNIEXPORT void JNICALL Java_HelloJNI_modifyInstanceVariable(JNIEnv* env, jobject thisObj){ |
//get reference to "this" object's class |
jclass thisClass = env->GetObjectClass(thisObj); |
|
//get Field ID of the instance variable "number" |
jfieldID fieldNumber = env->GetFieldID(thisClass, "number", "I"); //For a Java class, the field descriptor is in the form of "L<fully-qualified-name>;", with dot replaced by forward slash (/), e.g.,, the class descriptor for String is "Ljava/lang/String;". For primitives, use "I" for int, "B" for byte, "S" for short, "J" for long, "F" for float, "D" for double, "C" for char, and "Z" for boolean. For arrays, include a prefix "[", e.g., "[Ljava/lang/Object;" for an array of Object; "[I" for an array of int. You can list the method signature for a Java program via javap utility (Class File Disassembler) with -s (print signature) and -p (show private members) |
|
if (NULL == fieldNumber) return; |
|
//get int value given by FieldID |
jint number = env->GetIntField(thisObj, fieldNumber); |
//cout << "Number:" << number << endl; |
|
//change the variable |
number = 11; |
env->SetIntField(thisObj, fieldNumber, number); |
|
//Get the fieldID of the instance variable "message" |
jfieldID fieldMessage = env->GetFieldID(thisClass, "message", "Ljava/lang/String;"); |
if (NULL == fieldMessage) return; |
|
//get string variable from fieldMessage |
jstring message = (jstring) env->GetObjectField(thisObj, fieldMessage); |
|
//create a C++ string with JNI string |
const char* cppStr = env->GetStringUTFChars(message, NULL); |
if (NULL == cppStr) return; |
|
//cout << "Message = " << cppStr << endl; |
|
//Release resources |
env->ReleaseStringUTFChars(message, cppStr); |
|
//Create a new cpp String and assign to the JNI string |
message = env->NewStringUTF("Hello from C++"); |
if (NULL == message) return; |
|
env->SetObjectField(thisObj, fieldMessage, message); |
|
} |
|
|
//Modify static variable |
JNIEXPORT void JNICALL Java_HelloJNI_modifyStaticVariable(JNIEnv *env, jobject thisObj){ |
|
//get reference to the class |
jclass cls = env->GetObjectClass(thisObj); |
|
//read variable value |
jfieldID fieldNumber = env->GetStaticFieldID(cls, "staticNumber", "D"); |
if (NULL == fieldNumber) return; |
|
jdouble number = env->GetStaticDoubleField(cls, fieldNumber); |
//cout << "Static Number: " << number << endl; |
|
number = 3.14; |
//modifier static variable |
env->SetStaticDoubleField(cls, fieldNumber, number); |
|
} |
|
|
//callback java methods |
JNIEXPORT void JNICALL Java_HelloJNI_nativeMethod(JNIEnv *env, jobject thisObj){ |
//get reference to "this" object's class |
jclass thisClass = env->GetObjectClass(thisObj); |
jmethodID mCallback = env->GetMethodID(thisClass, "callback", "()V"); |
if (NULL == mCallback) return; |
env->CallVoidMethod(thisObj, mCallback); |
|
//call "callback(String)" |
jmethodID mCallbackMsg = env->GetMethodID(thisClass, "callback", "(Ljava/lang/String;)V"); |
if (NULL == mCallbackMsg) return; |
env->CallVoidMethod(thisObj, mCallbackMsg, env->NewStringUTF("Hello from ++") ); |
|
|
//call "callbackAverage(int, int)" |
jmethodID mCallbackAverage = env->GetMethodID(thisClass, "callbackAverage", "(II)D"); |
if (NULL == mCallbackAverage) return; |
cout << "Average: " << env->CallDoubleMethod(thisObj, mCallbackAverage, 2, 3) << endl; |
|
//call static method "callbackStatic" |
jmethodID mCallbackStatic = env->GetStaticMethodID(thisClass, "callbackStatic", "()Ljava/lang/String;"); |
if (NULL == mCallbackStatic) return; |
//type cast is important here in c++ |
jstring in_str = (jstring) env->CallStaticObjectMethod(thisClass, mCallbackStatic); |
const char* out_str = env->GetStringUTFChars(in_str, NULL); |
if (NULL == out_str) return; |
cout << "callback static string: " << out_str << endl; |
env->ReleaseStringUTFChars(in_str, out_str); |
|
//call super class method |
jmethodID mCallbackBaseClassMethod = env->GetMethodID(thisClass, "callBaseClass" ,"()V"); |
if (NULL == mCallbackBaseClassMethod) return; |
env->CallNonvirtualVoidMethod(thisObj, thisClass, mCallbackBaseClassMethod); |
} |
|
JNIEXPORT jobject JNICALL Java_HelloJNI_getIntegerObject(JNIEnv *env, jobject thisObj, jint number){ |
|
//get a reference for java.lang.Integer class |
jclass tempIntClass = env->FindClass("java/lang/Integer"); |
|
//you can save a integer class reference to a global reference for later use (you can't do that for jmethodID and jfieldID they aren't objects) |
intClass = (jclass) env->NewGlobalRef(tempIntClass); |
//no longer need the local reference |
env->DeleteLocalRef(tempIntClass); |
|
//get the methodID of the constructor which takes an int |
jmethodID mInit = env->GetMethodID(intClass, "<init>", "(I)V"); |
if (NULL == mInit) return NULL; |
//call back constructor to allocate a new instance with int argument |
jobject intObj = env->NewObject(intClass, mInit, number); |
|
//call to call ToString() on this object |
jmethodID mToString = env->GetMethodID(intClass, "toString", "()Ljava/lang/String;"); |
if (NULL == mToString) return NULL; |
|
jstring in_str = (jstring) env->CallObjectMethod(intObj, mToString); |
const char* out_str = env->GetStringUTFChars(in_str, NULL); |
cout << "Number in C++: " << out_str << endl; |
|
return intObj; |
} |
|
//call a method with Array of Object argument |
JNIEXPORT jobjectArray JNICALL Java_HelloJNI_sumAndAverage(JNIEnv *env, jobject thisObj, jobjectArray intArray){ |
//reference to java's Integer |
jclass intClass = env->FindClass("java/lang/Integer"); |
|
//use Integer.intValue() to retreive the int |
jmethodID mIntValue = env->GetMethodID(intClass, "intValue", "()I"); |
if (NULL == mIntValue) return NULL; |
|
//get the size of object array |
jsize length = env->GetArrayLength(intArray); |
jint sum = 0; |
for (int i = 0; i < length; i++){ |
jobject intObj = env->GetObjectArrayElement(intArray, i); |
if (NULL == intObj) return NULL; |
sum += env->CallIntMethod(intObj, mIntValue); // may need a cast! |
} |
double average = (double) sum / length; |
jclass classDouble = env->FindClass("java/lang/Double"); |
//allocate a jobjectArray of 2 Double |
jobjectArray outArray = env->NewObjectArray(2, classDouble, NULL); |
|
jmethodID mDoubleInit = env->GetMethodID(classDouble, "<init>", "(D)V"); |
if (NULL == mDoubleInit) return NULL; |
jobject objSum = env->NewObject(classDouble, mDoubleInit, (double) sum); |
jobject objAve = env->NewObject(classDouble, mDoubleInit, average); |
//set to the jobjectArray |
env->SetObjectArrayElement(outArray, 0, objSum); |
env->SetObjectArrayElement(outArray, 1, objAve); |
|
return outArray; |
} |
|
JNIEXPORT void JNICALL Java_HelloJNI_methodException(JNIEnv *env, jobject obj){ |
|
jthrowable exc; |
jclass cls = env->GetObjectClass(obj); |
jmethodID mid = env->GetMethodID(cls, "callbackException", "()V"); |
if (mid == NULL) return; |
//try { |
env->CallVoidMethod(obj, mid); |
//} catch (const std::exception& e){ |
//cout << "Exception thrown from native code" << endl; |
//} |
exc = env->ExceptionOccurred(); |
if (exc) { |
jclass newCls = env->FindClass("java/lang/IllegalArgumentException"); |
if (newCls == NULL) return; //unable to find exception, so just leave |
env->ExceptionDescribe(); |
env->ExceptionClear(); |
cout << "Exception thrown from native code" << endl; |
//raise the an IllegalArgumentException |
//env->ThrowNew(newCls, "Exception thrown from native code"); |
} |
} |
|
//call method with ArrayList type argument |
JNIEXPORT jobject JNICALL Java_HelloJNI_makeList(JNIEnv *env, jobject thisObj, jint i){ |
|
jclass arrClass = env->FindClass("java/util/ArrayList"); |
if (arrClass == NULL) return NULL; |
|
jmethodID initArr = env->GetMethodID(arrClass, "<init>", "(I)V"); |
if (initArr == NULL) return NULL; |
|
jmethodID arrSize = env->GetMethodID (arrClass, "size", "()I"); |
if (arrSize == NULL) return NULL; |
|
jobject arr = env->NewObject(arrClass, initArr); |
|
jmethodID arrAdd = env->GetMethodID(arrClass, "add", "(Ljava/lang/Object;)Z"); |
if (arrAdd == NULL) return NULL; |
|
jmethodID arrGet = env->GetMethodID(arrClass, "get", "(I)Ljava/lang/Object;"); |
if (arrGet == NULL) return NULL; |
|
for (int j = 1; j <= i; ++j) { |
jclass intClass = env->FindClass("java/lang/Integer"); |
jmethodID mInit = env->GetMethodID(intClass, "<init>", "(I)V"); |
jobject intObj = env->NewObject(intClass, mInit, j); |
jboolean reslt = (jboolean) env->CallBooleanMethod(arr, arrAdd, intObj); |
if (!reslt) |
return NULL; |
} |
|
jint size = (jint) env->CallIntMethod(arr, arrSize); |
cout << "ArrayList size: " << size << endl; |
|
return arr; |
|
} |