#ifndef JNIUtility_H
#define JNIUtility_H
//
#ifdef __cplusplus
extern "C" {
#endif
//
#include <jni.h>
//
/* Throw common exceptions */
/* Note: these have been macroized in jni_cvm_util.h */
void JNU_ThrowNullPointerException(JNIEnv *env, const char *msg);
void JNU_ThrowArrayIndexOutOfBoundsException(JNIEnv *env, const char *msg);
void JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg);
void JNU_ThrowIllegalArgumentException(JNIEnv *env, const char *msg);
void JNU_ThrowIllegalAccessError(JNIEnv *env, const char *msg);
void JNU_ThrowIllegalAccessException(JNIEnv *env, const char *msg);
void JNU_ThrowInternalError(JNIEnv *env, const char *msg);
void JNU_ThrowIOException(JNIEnv *env, const char *msg);
void JNU_ThrowNoSuchFieldException(JNIEnv *env, const char *msg);
void JNU_ThrowNoSuchMethodException(JNIEnv *env, const char *msg);
void JNU_ThrowClassNotFoundException(JNIEnv *env, const char *msg);
void JNU_ThrowNumberFormatException(JNIEnv *env, const char *msg);
void JNU_ThrowNoSuchFieldError(JNIEnv *env, const char *msg);
void JNU_ThrowNoSuchMethodError(JNIEnv *env, const char *msg);
void JNU_ThrowStringIndexOutOfBoundsException(JNIEnv *env, const char *msg);
void JNU_ThrowInstantiationException(JNIEnv *env, const char *msg);
/* Class constants */
jclass JNU_ClassString(JNIEnv *env);
jclass JNU_ClassClass(JNIEnv *env);
jclass JNU_ClassObject(JNIEnv *env);
jclass JNU_ClassThrowable(JNIEnv *env);
/* Copy count number of arguments from src to dst. Array bounds and ArrayStoreException are checked. */
jint JNU_CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src, jint count);
/* Invoke a object-returning static method, based on class name,
* method name, and signature string.
*
* The caller should check for exceptions by setting hasException
* argument. If the caller is not interested in whether an exception
* has occurred, pass in NULL.
*/
jvalue JNU_CallStaticMethod(JNIEnv *env, jboolean *hasException, const char *class_name, const char *name, const char *signature, ...);
/* Invoke an instance method by name. */
jvalue JNU_CallMethod(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature, ...);
jvalue JNU_CallMethodV(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature, va_list args);
/* Construct a new object of class, specifiying the class by name,
* and specififying which constructor to run and what arguments to
* pass to it.
*
* The method will return an initialized instance if successful.
* It will return NULL if an error has occured (for example if
* it ran out of memory) and the appropriate Java exception will
* have been thrown.
*/
jobject JNU_NewObject(JNIEnv *env, const char *class_name, const char *constructor_sig, ...);
/* returns:
* 0: object is not an instance of the class named by classname.
* 1: object is an instance of the class named by classname.
* -1: the class named by classname cannot be found. An exception
* has been thrown.
*/
jint JNU_IsInstanceOf(JNIEnv *env, jobject object, char *classname);
/* Get or set class and instance fields.
* Note that set functions take a variable number of arguments,
* but only one argument of the appropriate type can be passed.
* For example, to set an integer field i to 100:
*
* JNU_SetFieldByName(env, &exc, obj, "i", "I", 100);
*
* To set a float field f to 12.3:
*
* JNU_SetFieldByName(env, &exc, obj, "f", "F", 12.3);
*
* The caller should check for exceptions by setting hasException
* argument. If the caller is not interested in whether an exception
* has occurred, pass in NULL.
*/
jvalue JNU_GetField(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *sig);
void JNU_SetField(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *sig, ...);
jvalue JNU_GetStaticField(JNIEnv *env, jboolean *hasException, const char *classname, const char *name, const char *sig);
void JNU_SetStaticField(JNIEnv *env, jboolean *hasException, const char *classname, const char *name, const char *sig, ...);
/*
* Calls the .equals method.
*/
jboolean JNU_Equals(JNIEnv *env, jobject object1, jobject object2);
/************************************************************************
* Thread calls
*
* Convenience thread-related calls on the java.lang.Object class.
*/
void JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout);
void JNU_Notify(JNIEnv *env, jobject object);
void JNU_NotifyAll(JNIEnv *env, jobject object);
/************************************************************************
* Miscellaneous utilities used by the class libraries */
#define IS_NULL(obj) ((obj) == NULL)
/************************************************************************
* Debugging utilities
*/
jstring JNU_ToString(JNIEnv *env, jobject object);
/*
* Package shorthand for use by native libraries
*/
#define JNU_JAVAPKG "java/lang/"
#define JNU_JAVAIOPKG "java/io/"
#define JNU_JAVANETPKG "java/net/"
/*
* Check if the current thread is attached to the VM, and returns
* the JNIEnv of the specified version if the thread is attached.
*
* If the current thread is not attached, this function returns 0.
*
* If the current thread is attached, this function returns the
* JNI environment, or returns (void *)JNI_ERR if the specified
* version is not suppored.
*/
void *JNU_GetEnv(JavaVM *vm, jint version);
/*
* Warning free access to pointers stored in Java long fields.
*/
#define JNU_GetLongFieldAsPtr(env,obj,id) ((void *)(unsigned long)(*(env))->GetLongField((env),(obj),(id)))
#define JNU_SetLongFieldFromPtr(env,obj,id,val) (*(env))->SetLongField((env),(obj),(id),(jlong)(unsigned long)(val))
//
#ifdef __cplusplus
}
#endif
//
#endif
#include "JNIUtility.h"
#include "NativeHelper/JNIHelp.h"
#include <stdio.h>
#include <string.h>
//
void JNU_ThrowNullPointerException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NullPointerException", msg); }
void JNU_ThrowArrayIndexOutOfBoundsException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", msg); }
void JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/OutOfMemoryError", msg); }
void JNU_ThrowIllegalArgumentException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/IllegalArgumentException", msg); }
void JNU_ThrowIllegalAccessError(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/IllegalAccessError", msg); }
void JNU_ThrowIllegalAccessException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/IllegalAccessException", msg); }
void JNU_ThrowInternalError(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/InternalError", msg); }
void JNU_ThrowNoSuchFieldException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NoSuchFieldException", msg); }
void JNU_ThrowNoSuchMethodException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NoSuchMethodException", msg); }
void JNU_ThrowClassNotFoundException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/ClassNotFoundException", msg); }
void JNU_ThrowNumberFormatException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NumberFormatException", msg); }
void JNU_ThrowIOException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/io/IOException", msg); }
void JNU_ThrowNoSuchFieldError(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NoSuchFieldError", msg); }
void JNU_ThrowNoSuchMethodError(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/NoSuchMethodError", msg); }
void JNU_ThrowStringIndexOutOfBoundsException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/StringIndexOutOfBoundsException", msg); }
void JNU_ThrowInstantiationException(JNIEnv *env, const char *msg) { jniThrowException(env, "java/lang/InstantiationException", msg); }
//
jvalue JNU_CallStaticMethod(JNIEnv *env, jboolean *hasException, const char *class_name, const char *name, const char *signature, ...)
{
jclass clazz;
jmethodID mid;
va_list args;
jvalue result;
const char *p = signature;
/* find out the return type */
while (*p && *p != ')') {
p++;
}
p++;
result.i = 0;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
clazz = env->FindClass(class_name);
if (clazz == 0) {
goto done2;
}
mid = env->GetStaticMethodID(clazz, name, signature);
if (mid == 0) {
goto done1;
}
va_start(args, signature);
switch (*p) {
case 'V':
env->CallStaticVoidMethodV(clazz, mid, args);
break;
case '[':
case 'L':
result.l = env->CallStaticObjectMethodV(clazz, mid, args);
break;
case 'Z':
result.z = env->CallStaticBooleanMethodV(clazz, mid, args);
break;
case 'B':
result.b = env->CallStaticByteMethodV(clazz, mid, args);
break;
case 'C':
result.c = env->CallStaticCharMethodV(clazz, mid, args);
break;
case 'S':
result.s = env->CallStaticShortMethodV(clazz, mid, args);
break;
case 'I':
result.i = env->CallStaticIntMethodV(clazz, mid, args);
break;
case 'J':
result.j = env->CallStaticLongMethodV(clazz, mid, args);
break;
case 'F':
result.f = env->CallStaticFloatMethodV(clazz, mid, args);
break;
case 'D':
result.d = env->CallStaticDoubleMethodV(clazz, mid, args);
break;
default:
env->FatalError("JNU_CallStaticMethodByName: illegal signature");
break;
}
va_end(args);
done1:
env->DeleteLocalRef(clazz);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
return result;
}
jvalue JNU_CallMethod(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature, ...)
{
jvalue result;
va_list args;
va_start(args, signature);
result = JNU_CallMethodV(env, hasException, obj, name, signature, args);
va_end(args);
return result;
}
jvalue JNU_CallMethodV(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature, va_list args)
{
jclass clazz;
jmethodID mid;
jvalue result;
const char *p = signature;
/* find out the return type */
while (*p && *p != ')') {
p++;
}
p++;
result.i = 0;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
clazz = env->GetObjectClass(obj);
mid = env->GetMethodID(clazz, name, signature);
if (mid == 0) {
goto done1;
}
switch (*p) {
case 'V':
env->CallVoidMethodV(obj, mid, args);
break;
case '[':
case 'L':
result.l = env->CallObjectMethodV(obj, mid, args);
break;
case 'Z':
result.z = env->CallBooleanMethodV(obj, mid, args);
break;
case 'B':
result.b = env->CallByteMethodV(obj, mid, args);
break;
case 'C':
result.c = env->CallCharMethodV(obj, mid, args);
break;
case 'S':
result.s = env->CallShortMethodV(obj, mid, args);
break;
case 'I':
result.i = env->CallIntMethodV(obj, mid, args);
break;
case 'J':
result.j = env->CallLongMethodV(obj, mid, args);
break;
case 'F':
result.f = env->CallFloatMethodV(obj, mid, args);
break;
case 'D':
result.d = env->CallDoubleMethodV(obj, mid, args);
break;
default:
env->FatalError("JNU_CallMethodByNameV: illegal signature");
break;
}
done1:
env->DeleteLocalRef(clazz);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
return result;
}
jobject JNU_NewObject(JNIEnv *env, const char *class_name, const char *constructor_sig, ...)
{
jobject obj = NULL;
jclass cls = 0;
jmethodID cls_initMID;
va_list args;
if (env->EnsureLocalCapacity(2) < 0) {
goto done;
}
cls = env->FindClass(class_name);
if (cls == 0) {
goto done;
}
cls_initMID = env->GetMethodID(cls, "<init>", constructor_sig);
if (cls_initMID == NULL) {
goto done;
}
va_start(args, constructor_sig);
obj = env->NewObjectV(cls, cls_initMID, args);
va_end(args);
done:
env->DeleteLocalRef(cls);
return obj;
}
/* Note: JNU_ClassString, JNU_ClassClass, JNU_ClassObject, JNU_ClassThrowable */
jclass JNU_ClassString(JNIEnv *env)
{
static jclass cls = 0;
if (cls == 0) {
jclass c;
if (env->EnsureLocalCapacity(1) < 0) {
return 0;
}
c = env->FindClass("java/lang/String");
cls = reinterpret_cast<jclass>(env->NewGlobalRef(c));
env->DeleteLocalRef(c);
}
return cls;
}
jclass JNU_ClassClass(JNIEnv *env)
{
static jclass cls = 0;
if (cls == 0) {
jclass c;
if (env->EnsureLocalCapacity(1) < 0) {
return 0;
}
c = env->FindClass("java/lang/Class");
cls = reinterpret_cast<jclass>(env->NewGlobalRef(c));
env->DeleteLocalRef(c);
}
return cls;
}
jclass JNU_ClassObject(JNIEnv *env)
{
static jclass cls = 0;
if (cls == 0) {
jclass c;
if (env->EnsureLocalCapacity(1) < 0) {
return 0;
}
c = env->FindClass("java/lang/Object");
cls = reinterpret_cast<jclass>(env->NewGlobalRef(c));
env->DeleteLocalRef(c);
}
return cls;
}
jclass JNU_ClassThrowable(JNIEnv *env)
{
static jclass cls = 0;
if (cls == 0) {
jclass c;
if (env->EnsureLocalCapacity(1) < 0) {
return 0;
}
c = env->FindClass("java/lang/Throwable");
cls = reinterpret_cast<jclass>(env->NewGlobalRef(c));
env->DeleteLocalRef(c);
}
return cls;
}
jint JNU_CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src, jint count)
{
if (env->EnsureLocalCapacity(1) < 0) {
return -1;
}
for (int i = 0; i < count; i++) {
jstring p = (jstring) env->GetObjectArrayElement(src, i);
env->SetObjectArrayElement(dst, i, p);
env->DeleteLocalRef(p);
}
return 0;
}
void * JNU_GetEnv(JavaVM *vm, jint version)
{
void *env = NULL;
vm->GetEnv(&env, version);
return env;
}
jint JNU_IsInstanceOf(JNIEnv *env, jobject object, char *classname)
{
jclass cls;
if (env->EnsureLocalCapacity(1) < 0) {
return JNI_ERR;
}
cls = env->FindClass(classname);
if (cls != NULL) {
jint result = env->IsInstanceOf(object, cls);
env->DeleteLocalRef(cls);
return result;
}
return JNI_ERR;
}
/************************************************************************
* Debugging utilities
*/
jstring JNU_ToString(JNIEnv *env, jobject object)
{
if (object == NULL) {
return env->NewStringUTF("NULL");
}
else {
return reinterpret_cast<jstring>(JNU_CallMethod(env, NULL, object, "toString", "()Ljava/lang/String;").l);
}
}
jvalue JNU_GetField(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature)
{
jclass cls;
jfieldID fid;
jvalue result;
result.i = 0;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
cls = env->GetObjectClass(obj);
fid = env->GetFieldID(cls, name, signature);
if (fid == 0) {
goto done1;
}
switch (*signature) {
case '[':
case 'L':
result.l = env->GetObjectField(obj, fid);
break;
case 'Z':
result.z = env->GetBooleanField(obj, fid);
break;
case 'B':
result.b = env->GetByteField(obj, fid);
break;
case 'C':
result.c = env->GetCharField(obj, fid);
break;
case 'S':
result.s = env->GetShortField(obj, fid);
break;
case 'I':
result.i = env->GetIntField(obj, fid);
break;
case 'J':
result.j = env->GetLongField(obj, fid);
break;
case 'F':
result.f = env->GetFloatField(obj, fid);
break;
case 'D':
result.d = env->GetDoubleField(obj, fid);
break;
default:
env->FatalError("JNU_GetFieldByName: illegal signature");
break;
}
done1:
env->DeleteLocalRef(cls);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
return result;
}
void JNU_SetField(JNIEnv *env, jboolean *hasException, jobject obj, const char *name, const char *signature, ...)
{
jclass cls;
jfieldID fid;
va_list args;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
cls = env->GetObjectClass(obj);
fid = env->GetFieldID(cls, name, signature);
if (fid == 0) {
goto done1;
}
/* When passing arguments via '...', each argument is converted to int
or double (as appropriate). When we pick off the mystery argument
with va_arg(), we need to use the type of argument as passed, not
the type we want. The compiler will convert the argument back to the
proper type when passing it to Set<type>Field(). */
va_start(args, signature);
switch (*signature) {
case '[':
case 'L':
env->SetObjectField(obj, fid, va_arg(args, jobject));
break;
case 'Z':
env->SetBooleanField(obj, fid, (jboolean) va_arg(args, jint));
break;
case 'B':
env->SetByteField(obj, fid, (jbyte) va_arg(args, jint));
break;
case 'C':
env->SetCharField(obj, fid, (jchar) va_arg(args, jint));
break;
case 'S':
env->SetShortField(obj, fid, (jshort) va_arg(args, jint));
break;
case 'I':
env->SetIntField(obj, fid, va_arg(args, jint));
break;
case 'J':
env->SetLongField(obj, fid, va_arg(args, jlong));
break;
case 'F':
env->SetFloatField(obj, fid, (jfloat) va_arg(args, jdouble));
break;
case 'D':
env->SetDoubleField(obj, fid, va_arg(args, jdouble));
break;
default:
env->FatalError("JNU_SetFieldByName: illegal signature");
break;
}
va_end(args);
done1:
env->DeleteLocalRef(cls);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
}
jvalue JNU_GetStaticField(JNIEnv *env, jboolean *hasException, const char *classname, const char *name, const char *signature)
{
jclass cls;
jfieldID fid;
jvalue result;
result.i = 0;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
cls = env->FindClass(classname);
if (cls == 0) {
goto done2;
}
fid = env->GetStaticFieldID(cls, name, signature);
if (fid == 0) {
goto done1;
}
switch (*signature) {
case '[':
case 'L':
result.l = env->GetStaticObjectField(cls, fid);
break;
case 'Z':
result.z = env->GetStaticBooleanField(cls, fid);
break;
case 'B':
result.b = env->GetStaticByteField(cls, fid);
break;
case 'C':
result.c = env->GetStaticCharField(cls, fid);
break;
case 'S':
result.s = env->GetStaticShortField(cls, fid);
break;
case 'I':
result.i = env->GetStaticIntField(cls, fid);
break;
case 'J':
result.j = env->GetStaticLongField(cls, fid);
break;
case 'F':
result.f = env->GetStaticFloatField(cls, fid);
break;
case 'D':
result.d = env->GetStaticDoubleField(cls, fid);
break;
default:
env->FatalError("JNU_GetStaticFieldByName: illegal signature");
break;
}
done1:
env->DeleteLocalRef(cls);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
return result;
}
void JNU_SetStaticField(JNIEnv *env, jboolean *hasException, const char *classname, const char *name, const char *signature, ...)
{
jclass cls;
jfieldID fid;
va_list args;
if (env->EnsureLocalCapacity(3) < 0) {
goto done2;
}
cls = env->FindClass(classname);
if (cls == 0) {
goto done2;
}
fid = env->GetStaticFieldID(cls, name, signature);
if (fid == 0) {
goto done1;
}
/* When passing arguments via '...', each argument is converted to int
or double (as appropriate). When we pick off the mystery argument
with va_arg(), we need to use the type of argument as passed, not
the type we want. The compiler will convert the argument back to the
proper type when passing it to SetStatic<type>Field(). */
va_start(args, signature);
switch (*signature) {
case '[':
case 'L':
env->SetStaticObjectField(cls, fid, va_arg(args, jobject));
break;
case 'Z':
env->SetStaticBooleanField(cls, fid, (jboolean) va_arg(args, jint));
break;
case 'B':
env->SetStaticByteField(cls, fid, (jbyte) va_arg(args, jint));
break;
case 'C':
env->SetStaticCharField(cls, fid, (jchar) va_arg(args, jint));
break;
case 'S':
env->SetStaticShortField(cls, fid, (jshort) va_arg(args, jint));
break;
case 'I':
env->SetStaticIntField(cls, fid, va_arg(args, jint));
break;
case 'J':
env->SetStaticLongField(cls, fid, va_arg(args, jlong));
break;
case 'F':
env->SetStaticFloatField(cls, fid, (jfloat) va_arg(args, jdouble));
break;
case 'D':
env->SetStaticDoubleField(cls, fid, va_arg(args, jdouble));
break;
default:
env->FatalError("JNU_SetStaticFieldByName: illegal signature");
break;
}
va_end(args);
done1:
env->DeleteLocalRef(cls);
done2:
if (hasException) {
*hasException = env->ExceptionCheck();
}
}
jboolean JNU_Equals(JNIEnv *env, jobject object1, jobject object2)
{
return JNU_CallMethod(env, NULL, object1, "equals", "(Ljava/lang/Object;)Z", object2).z;
}
void JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout)
{
if (object == NULL) {
JNU_ThrowNullPointerException(env, "JNU_MonitorWait argument");
return;
}
JNU_CallMethod(env, NULL, object, "wait", "(J)V", timeout);
}
void JNU_Notify(JNIEnv *env, jobject object)
{
if (object == NULL) {
JNU_ThrowNullPointerException(env, "JNU_Notify argument");
return;
}
JNU_CallMethod(env, NULL, object, "notify", "()V");
}
void JNU_NotifyAll(JNIEnv *env, jobject object)
{
if (object == NULL) {
JNU_ThrowNullPointerException(env, "JNU_NotifyAll argument");
return;
}
JNU_CallMethod(env, NULL, object, "notifyAll", "()V");
}