Java Native Interface Modified from CS 587 x

  • Slides: 28
Download presentation
Java Native Interface Modified from CS 587 x Lecture Department of Computer Science Iowa

Java Native Interface Modified from CS 587 x Lecture Department of Computer Science Iowa State University

Introduction What is native method What is Java Native Interface (JNI) Why we use

Introduction What is native method What is Java Native Interface (JNI) Why we use JNI How to use JNI Embedding C in Java n Using Java features from C n Embedding the VM n

What is Native Method Functions written in a language other than Java They could

What is Native Method Functions written in a language other than Java They could be C, C++, or even assembly

What is JNI Java interface to non-Java code. It is Java's link to the

What is JNI Java interface to non-Java code. It is Java's link to the "outside world" n n Native methods are compiled into a dynamic link library (. dll, . so, etc. ) OS loads and links the library into the process that is running the Java Virtual Machine Part of the Java Developer Kit(JDK), serves as a glue between java side and native side of an application n Allows Java code that runs inside a Java Virtual Machine (JVM) to interoperate with applications and libraries written in other programming languages, such as C, C++, and assembly

JNI Overview

JNI Overview

Why Use JNI Some functionality are not provided by java n Low-level drives/devices specific

Why Use JNI Some functionality are not provided by java n Low-level drives/devices specific to OS Increase performance by implementing rigorous tasks in native language n Java is slow in general and may not be suitable for some functions (e. g. , image compression and decompression) Try to use existing legacy library and could not afford to rewrite it in java n n JNI can be used as a wrapper of these legacy codes Can slowly migrate legacy code to a newer platform Improve efficiency of integration n TCP/IP sockets can be used, but there are overhead in data transmission

Justification Pros: n n Reuse: allows access to useful native code Efficiency: use best

Justification Pros: n n Reuse: allows access to useful native code Efficiency: use best language for the task Cons: n n Portability: native methods aren't portable Extra work: javah, create shared native libs

Interactions with Native Code Access to Java world from native code Access to native

Interactions with Native Code Access to Java world from native code Access to native code from Java

Using The JNI Java calls C n Embedding C in Java C calls Java

Using The JNI Java calls C n Embedding C in Java C calls Java Using Java features from C n Embedding the VM n

Embedding C in Java 1. 2. 3. 4. 5. Declare the method using the

Embedding C in Java 1. 2. 3. 4. 5. Declare the method using the keyword native, provide no implementation. Make sure the Java loads the needed library Run the javah utility to generate names/headers Implement the method in C Compile as a shared library class Hello. World { public native void display. Hello. World(); static { System. load. Library("hello"); } public static void main(String[] args) { new Hello. World(). display. Hello. World(); } }

Generate JNI Header Compile Hello. World. java n javac Hello. World. java Generate Hello.

Generate JNI Header Compile Hello. World. java n javac Hello. World. java Generate Hello. World. h n javah Hello. World

Hello. World. h #include “jni. h” /* Header for class Hello. World */ #ifndef

Hello. World. h #include “jni. h” /* Header for class Hello. World */ #ifndef _Included_Hello. World #define _Included_Hello. World #ifdef __cplus extern “C” { #endif /* * Class: Hello. World * Method: display. Hello. World * Signature: ()V */ JNIEXPORT void JNICALL Java_Hello. World_display. Hello. World(JNIEnv *env, jobject); #ifdef __cplus } #endif The JVM reference The calling object

Hello. World. Imp. c #include <jni. h> #include "Hello. World. h" #include <stdio. h>

Hello. World. Imp. c #include <jni. h> #include "Hello. World. h" #include <stdio. h> JNIEXPORT void JNICALL Java_Hello. World_display. Hello. World(JNIEnv *env, jobject obj) { printf("Hello world!n"); return; }

Create a Shared Library class Hello. World {. . . } . . .

Create a Shared Library class Hello. World {. . . } . . . System. load. Library("hello"); Compile the native code into a shared library: n popeye (Linux) cc -shared -I/usr/java/j 2 sdk 1. 4. 1_04/include -I/usr/java/j 2 sdk 1. 4. 1_04/include/linux Hello. World. Impl. c -o libhello. so -Wl, --add-stdcall-alias In my Windows, it is needed!

Reference --add-stdcall-alias If given, symbols with a stdcall suffix (@nn) will be exported as

Reference --add-stdcall-alias If given, symbols with a stdcall suffix (@nn) will be exported as -is and also with the suffix stripped. http: //en. wikipedia. org/wiki/X 86_calling _conventions http: //en. wikipedia. org/wiki/Name_man gling

Run the Program Command: java Hello. World Result: Hello World! Possible exceptions: java. lang.

Run the Program Command: java Hello. World Result: Hello World! Possible exceptions: java. lang. Unsatisfied. Link. Error: no hello in shared library path at java. lang. Runtime. load. Library(Runtime. java) at java. lang. System. load. Library(System. java) at java. lang. Thread. init(Thread. java) On popeye (Linux), do this: LD_LIBRARY_PATH=. / export LD_LIBRARY_PATH

Primitive Types and Native Equivalents Java Type Native Type Size in bits boolean jboolean

Primitive Types and Native Equivalents Java Type Native Type Size in bits boolean jboolean 8, unsigned byte jbyte 8 char jchar 16, unsigned short jshort 16 int jint 32 long jlong 64 float jfloat 32 double jdouble 64 void n/a Each element of Java language must have a corresponding native counterpart • Platform-specific implementation • Generic interface to programmer

Object Types and Native Equivalents

Object Types and Native Equivalents

Mapping Example class Prompt { private native String get. Line(String prompt); } JNIEXPORT jstring

Mapping Example class Prompt { private native String get. Line(String prompt); } JNIEXPORT jstring JNICALL Java_Prompt_get. Line(JNIEnv *, jobject, jstring); Prefix + fully qualified class name + “_” + method name

Accessing Java Strings This jstring type is different from the regular C string type

Accessing Java Strings This jstring type is different from the regular C string type /* Illegal */ JNIEXPORT jstring JNICALL Java_Prompt_get. Line(JNIEnv *env, jobject obj, jstring prompt) { printf("%s", prompt); . . . } /* correct way */ JNIEXPORT jstring JNICALL Java_Prompt_get. Line(JNIEnv *env, jobject obj, jstring prompt) { const char *str = (*env)->Get. String. UTFChars(env, prompt, 0); printf("%s", str); } /* release the memory allocated for the string operation */ (*env)->Release. String. UTFChars(env, prompt, str); . . . For the functions associated with JNI objects, go to web page: http: //java. sun. com/j 2 se/1. 3/docs/guide/jni/spec/jni. TOC. doc. html

Accessing Java Array /* Illegal */ JNIEXPORT jint JNICALL Java_Int. Array_sum. Array(JNIEnv *env, jobject

Accessing Java Array /* Illegal */ JNIEXPORT jint JNICALL Java_Int. Array_sum. Array(JNIEnv *env, jobject obj, jint. Array arr) { int i, sum = 0; for (i=0; i<10; i++) { sum += arr[i]; }. . . /* correct way */ JNIEXPORT jint JNICALL Java_Int. Array_sum. Array(JNIEnv *env, jobject obj, jint. Array arr) { int i, sum = 0; /* 1. obstain the length of the array */ jsize len = (*env)->Get. Array. Length(env, arr); /* 2. obtain a pointer to the elements of the array */ jint *body = (*env)->Get. Int. Array. Elements(env, arr, 0); /* 3. operate on each individual primitive or jobjects */ for (i=0; i<len; i++) { sum += body[i]; } /* 4. release the memory allocated for array */ (*env)->Release. Int. Array. Elements(env, arr, body, 0);

Accessing Java Member Variables class Field. Access { static int si; /* signature is

Accessing Java Member Variables class Field. Access { static int si; /* signature is “si” */ String s; } /* signature is “Ljava/lang/String; "; /* run javap -s -p Field. Access to get the signature */ fid = (*env)->Get. Static. Field. ID(env, cls, "si", "I"); /* 1. get the field ID */ si = (*env)->Get. Static. Int. Field(env, cls, fid); /* 2. find the field variable */ (*env)->Set. Static. Int. Field(env, cls, fid, 200); /* 3. perform operation on the primitive*/ fid = (*env)->Get. Field. ID(env, cls, "s", "Ljava/lang/String; "); /* 1. get the field ID */ jstr = (*env)->Get. Object. Field(env, obj, fid); /* 2. find the field variable */ jstr = (*env)->New. String. UTF(env, "123"); /* 3. perform operation on the object */ (*env)->Set. Object. Field(env, obj, fid, jstr);

Calling a Java Method 1. Find the class of the object Call Get. Object.

Calling a Java Method 1. Find the class of the object Call Get. Object. Class 2. Find the method ID of the object Call Get. Method. ID, which performs a lookup for the Java method in a given class 3. Call the method JNI provides an API for each type of method e. g. , Call. Void. Method(), etc. You pass the object, method ID, and the actual arguments to the method (e. g. , Call. Void. Method) Example of Call: jclass cls = (*env)->Get. Object. Class(env, obj); jmethod. ID mid = (*env)->Get. Method. ID(env, cls, “hello”, “(I)V”); (*env)->Call. Void. Method(env, obj, mid, parm 1);

Garbage Collection Issues Only Arrays and explicitly globally created objects are “pinned” down and

Garbage Collection Issues Only Arrays and explicitly globally created objects are “pinned” down and must be explicitly released Everything else is released upon the native method returning

Thread Issues The JNI interface pointer (JNIEnv *) is only valid in the current

Thread Issues The JNI interface pointer (JNIEnv *) is only valid in the current thread You must not pass the interface pointer from one thread to another n You must not pass local references from one thread to another n Check the use of global variables carefully (locking is needed) n

Synchronization Synchronize is available as a C call Wait and Notify calls through JNIEnv

Synchronization Synchronize is available as a C call Wait and Notify calls through JNIEnv do work and are safe to use Could use native threading operations for native to native threading, but this may cost portability In java: synchronized (obj) {. . . /* synchronized block */. . . } In C: (*env)->Monitor. Enter(env, obj); /* synchronized block */ (*env)->Monitor. Exit(env, obj);

Embedding a VM in C Just a special kind of Java Call from C

Embedding a VM in C Just a special kind of Java Call from C (see reference) You get a pointer into your resulting environment and by the VM are treated as a native method With the exception you never “return” so it is your responsibility to do everything globally

References http: //java. sun. com/j 2 se/1. 3/docs/guide/jni/spec/jni. TOC. doc. html

References http: //java. sun. com/j 2 se/1. 3/docs/guide/jni/spec/jni. TOC. doc. html