| Platform | Tool Documentation | local copy |
|---|---|---|
| Solaris, Linux | javah | javah |
| Windows | javah | javah |
native return type method (arguments);
include/jni.h
static {
System.loadLibrary("dynamic libary");
}
| action | GNU | Windows |
|---|---|---|
| compile | gcc | cl |
| link | ln | link |
| action | Solaris | Windows |
|---|---|---|
| compile | -G | /LD |
| link | -G | /dll |
| library file | libname.so | name.dll |
javac HelloWorld.java
javah -jni HelloWorld
HelloWorld.h
include include/jni.h in the Java system install directory.
jni.h contains C/C++ function prototypes and includes system dependent file
jni_md.h.
jni.h
gcc -I/software/java/jdk1.2.2/include -I/software/java/jdk1.2.2/include/solaris -c HelloWorld.c -o HelloWorld.o
ld -G HelloWorld.o -o libHelloWorld.so
java -Djava.library.path=. HelloWorld
Hello World!
(Could do setenv LD_LIBRARY_PATH . on Unix instead.)
The current directory "." appears to be on the default path used
by Java to load libraries.
JNIEXPORT void JNICALL
Java_ ... (JNIENV *env, ...) {
(*env)->GetFieldID (env, ...);
}
JNIEXPORT void JNICALL
Java_ ... (JNIENV *env, ...) {
env->GetFieldID (...);
}
> java -Djava.library.path=. Access A private variable = 0 A private variable = 97 A static private variable = 0 A static private variable = 101
jclass c = (*env)->GetObjectClass(env, this); jfieldID fid = (*env)->GetFieldID(env, c, "private_variable", "I"); (*env)->SetIntField (env, this, fid, val);
jclass c = (*env)->GetObjectClass(env, this); jfieldID fid = (*env)->GetFieldID(env, c, "private_variable", "I"); jint val = (*env)->GetIntField(env, this, fid);
jclass c = (*env)->GetObjectClass(env, this);
JNIEXPORT void JNICALL
Java_AccessOther_setPrivate (JNIENV *env, jobject this, jobject other, jint val) {
jclass c = (*env)->GetObjectClass(env, other);
}
| Java Type | JNI Type | machine dependent C/C++ typedef | Signature | Call...Method Get...Field |
|---|---|---|---|---|
boolean | jboolean | unsigned char | Z | Boolean |
byte | jbyte | signed char | B | Byte |
char | jchar | unsigned short | C | Char |
short | jshort | short | S | Short |
int | jint | int | I | Int |
long | jlong | long | J | Long |
float | jfloat | float | F | Float |
double | jdouble | double | D | Double |
void | void | V | Void | |
| nonprimitive | jobject | *... | L...; | Object
|
| method definition | signature |
|---|---|
| int m1 () | ()I |
| double m2 (long l, char c) | (JC)D |
| void m3 (String s, int[] a) | (Ljava/lang/String;[I)V |
| String m4 (boolean b) | (Z)Ljava/lang/String; |
| Object m4 (BigDecimal b) | (Ljava/math/BigDecimal;)Ljava/lang/Object; |
private String getLine (String) (Ljava/lang/String;)Ljava/lang/String; public static void main (String [] args) ([Ljava/lang/String;)V
getMethodID (JNIEnv, jclass, char* name, char* descriptor)
There are three forms of calling a Java method:
JNI type CalltypeMethod (jobject, jmethodID, arguments); JNI type CallStatictypeMethod (jobject, jmethodID, arguments); JNI type CallNonvirtualtypeMethod (jobject, jmethodID, arguments);
Constructors are named <inti>.
There are three forms for passing the unknown number of arguments:
jvalue* (an array)
va_list
JNItypeCalltypeMethod (jobject obj, jmethodID mid, ...); JNItypeCalltypeMethodA (jobject obj, jmethodID mid, jvalue* args); JNItypeCalltypeMethodV (jobject obj, jmethodID mid, va_list args);
NewObjectArray GetArrayLength SetObjectElement
JNIEXPORT jstring JNICALL
Java_Strings_printString (JNIEnv *env, jclass this, jstring str) {
const char* utf_string;
jboolean is_copy;
utf_string = env->GetStringUTFChars (str, &isCopy);
printf ("%s\n", utf_string);
if (isCopy == JNI_TRUE) {
env->ReleaseStringUTFChars (str, utf_string);
}
}
How to create a Java string in native code:
JNIEXPORT jstring JNICALL
Java_NewString_newStringUTF (JNIEnv *env, jclass this) {
const char* msg = "String constructed using NewStringUTF";
return env->NewStringUTF(msg);
}
jclass cls = (*env)->FindClass (env, "java/lang/IllegalArgumentException"); if (cls==NULL) return; // Give up (*env)->ThrowNew (env, cls, "message"); return;
(*env)->CalltypeMethod (env, obj, method_id)
jthrowable exc = (*env)->ExceptionOccurred(env)
if (exc) {
(*env)->ExceptionClear(env)
}
int main (int argc, char *argv[]) {
JNIEnv *env;
JavaVM *jvm;
int i;
JDK1_1InitArgs vm_args; // env variables to control invocation
jint ret;
jmethodID mid;
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
int len = strlen(MY_CLASSPATH) + strlen(vm_args.classpath) + 1;
char * newcp = (char*) malloc(len * sizeof(char));
strcpy(newcp, MY_CLASSPATH);
strcat(newcp, vm_args.classpath);
vm_args.classpath = newcp;
vm_args.properties = properties;
vm_args.vfprintf = y_fprintf;
vm_args.exit = y_exit;
vm_args.abort = y_abort;
ret = JNI_CreateJavaVM(&jvm,&env,&vm_args);
if (ret < 0) {
fprintf(stderr, "Can't create Java VM. Error: %ld\n", ret);
return(1);
}
if (argc < 2) {
printf("No class specified. Exiting...\n\n");
return(-1);
}
jstring jstr = env->NewStringUTF("");
jobjectArray str_array =
env->NewObjectArray(argc-2, env->FindClass("java/lang/String"), jstr);
// Pass main arguments to Java
for( i = 2; i < argc; i++ ) {
jstr = env->NewStringUTF (argv[i]);
if (jstr == 0) {
fprintf(stderr, "Out of memory\n");
return(1);
}
env->SetObjectArrayElement( str_array, i - 2, jstr);
}
jclass clazz = env->FindClass(dotsToSlashes(argv[1]));
if (clazz == 0) {
fprintf(stderr, "Can't locate the %s class. Exiting...\n", argv[1]);
return(1);
}
mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
if (mid == 0) {
fprintf(stderr, "Can't locate the main method. Exiting...\n");
return(1);
}
env->CallStaticVoidMethod (clazz, mid, str_array);
jvm->DestroyJavaVM();
return(0);
}