Java Native Interface JNI JNI Linking Java and

  • Slides: 31
Download presentation
Java Native Interface (JNI)

Java Native Interface (JNI)

JNI Linking Java and C code

JNI Linking Java and C code

JNI • Stands for “Java Native Interface” • Set of tools/code that allows user

JNI • Stands for “Java Native Interface” • Set of tools/code that allows user to call “native” methods from Java. • Includes “bindings” for C/C++. • Can be used to call C/C++ from Java (typical), or Java from C (invocation API) • Differs from spawning executable – data is passed to/from C/C++ method • Question: why is this difficult?

Reasons for using JNI • Feature not available in java language (rare). • Code

Reasons for using JNI • Feature not available in java language (rare). • Code already written in another language, don’t want to rewrite (typical). • Java is slow (how slow? ) • Other language has no additional features per se, but has much better syntax for handling certain operations (Fortran for math).

Problems with JNI • Only provides C/C++ bindings. Going to Fortran, COBOL, Ada, etc.

Problems with JNI • Only provides C/C++ bindings. Going to Fortran, COBOL, Ada, etc. requires extra step. • Not portable • Mapping is not trivial • Can be unsafe • Cannot run from applet (security issues)

Machinery for using JNI Steps to follow …

Machinery for using JNI Steps to follow …

Basic steps to calling native code 1. Write java class with at least one

Basic steps to calling native code 1. Write java class with at least one method declared with native keyword. Provide no implementation – public native void say. Hello(); – Example above is most simple, but method may pass any parameters or have any return type. 2. Add a call to System. load. Library(“libname”) in the class that declares the native method: – static{ System. load. Library(“hello”); }//static means called only once.

Steps, cont. 3. Compile the class – javac Hello. java 4. Produce the C/C++

Steps, cont. 3. Compile the class – javac Hello. java 4. Produce the C/C++ header files using the javah utility: – – Javah Hello This produces the header file Hello. h 5. Write your implementation file by first copying the function signature produced in the include file. Also, #include the header file. #include “Hello. h”

Steps, cont. 6. Write the implementation in C/C++. This will require using JNI methods

Steps, cont. 6. Write the implementation in C/C++. This will require using JNI methods to access the data or possibly casts to convert to basic C/C++ types 7. Best technique: Break into two steps. Think of your C/C++ function as a wrapper which accesses the Java data and maps it to C data using JNI methods, then shoves the converted data into a prewritten standalone C program.

Steps, cont. 8. Compile your native method(s) as a shared object (or DLL on

Steps, cont. 8. Compile your native method(s) as a shared object (or DLL on Windows). – WARNING: Be sure to point your linker to the include files in /jdk 1. 3/include and jdk 1. 3/include/linux (for example). – WARNING: Mixing languages is much easier using a straight C wrapper rather than C++. 9. Set the environment variable LD_LIBRARY_PATH to the shared object directory • Run main Java class.

C language bindings What does Java pass to my method?

C language bindings What does Java pass to my method?

What does Java pass to my C function? • JNIEnv* : A pointer to

What does Java pass to my C function? • JNIEnv* : A pointer to the JNI environment. This pointer is a handle to the current thread in the JVM, and contains mapping functions and other housekeeping information. • jobject : A reference to the object that called the native code. (like “this” pointer). • Any arguments specified by the method.

Simple examples online • Hello. World Example: No data passed – Hello. java –

Simple examples online • Hello. World Example: No data passed – Hello. java – Hello. cc • Max example : Only native dataypes – Utils. java – utils. cc • Advanced Max example: Arrays – Utils. java – utils. cc • Max Java-C-Fortran: max. f

Native datatype mappings Java Type boolean byte char short int long float double void

Native datatype mappings Java Type boolean byte char short int long float double void Native Type jboolean jbyte jchar jshort jint jlong jfloat jdouble void Size in bits 8, unsigned 8 16, unsigned 16 32 64 N/a

Java object Mappings • Object passed by reference • All objects have type jobject

Java object Mappings • Object passed by reference • All objects have type jobject as:

Object mappings, cont. • For example, if a method get. Line exists in a

Object mappings, cont. • For example, if a method get. Line exists in a class call Prompt, then: private native String get. Line(String Prompt); is mapped into JNIExport jstring JNICALL Java_Prompt_get. Line(JNIEnv *, jobject, jstring); • But how to access data/methods from object that is passed in?

JNI Advice • Can seem like a bewildering number of functions. • Do not

JNI Advice • Can seem like a bewildering number of functions. • Do not try to learn it all. • Keep interfaces very simple. – Preferably, only native datatypes, Strings, and arrays. • Be careful about – Copies vs. rerences – Freeing memory • Best not to allocate memory from with native code.

Accessing java strings • Do NOT do the following: JNIEXPORT jstring JNICALL Java_Prompt_get. Line(JNIEnv

Accessing java strings • Do NOT do the following: JNIEXPORT jstring JNICALL Java_Prompt_get. Line(JNIEnv *env, jobject obj, jstring prompt){ printf(“%s”, prompt); } • Why is this bad?

Right way to access Strings • Must use special methods in env structure char

Right way to access Strings • Must use special methods in env structure char *str = (*env)->Get. String. UTFChars(env, prompt, 0); /* this maps into regular C char* */ printf(“%s”, str); /* now it is ok to print */ (*env)->Release. String. UTFChars(env, prompt, str); /* must release String to avoid memory leaks */

Returning Strings • Previous technique allows us to use a String passed in from

Returning Strings • Previous technique allows us to use a String passed in from Java. • What if we want to return a String? • Can use New. String. UTF as: char buf[128]; /* allocate memory for local char* in C */ scanf(“%s”, buf); /* read into char* from stdio */ return( (*env)->New. String. UTF(env, buf)); /* construct and return the Java String */

Other JNI String methods • Get. String. Chars – Takes the Java String and

Other JNI String methods • Get. String. Chars – Takes the Java String and returns a pointer to an array of Unicode characters that comprise it. • Release. String. Chars – Releases the pointer to the array of Unicode characters • New. String – Constructs a new String object from an array of Unicode Characters • Get. String. Length – Returns the length of a string of Unicode characters

Java arrays • Note that you can NOT do the following: JNIExport jint JNICALL

Java arrays • Note that you can NOT do the following: 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]; /* NO! – why not? }. . . • Must use java methods to access array data in C

Array methods • The previous example should be written as: jsize len = (*env)->Get.

Array methods • The previous example should be written as: jsize len = (*env)->Get. Array. Length(env, arr); jint *body = (*env)->Get. Int. Array. Elements(env, arr, 0); for (i=0; i<len; ++i){ sum += body[i]; } (*env)->Releast. Int. Array. Elements(env, arr, body, 0); /* very important – copies back to java array if copy had to be made */

Array methods, cont. • Note that there analagous functions for float, byte, double, etc:

Array methods, cont. • Note that there analagous functions for float, byte, double, etc: – Get<type>Array. Elements – Release<type>Array. Elements • Important: These Get functions may copy the entire array. If this is undesirable, use Get/Set<type>Array. Region functions

Function for accessing arrays Function Get. Boolean. Array. Elements Get. Byte. Array. Elements Get.

Function for accessing arrays Function Get. Boolean. Array. Elements Get. Byte. Array. Elements Get. Short. Array. Elements Get. Int. Array. Elements Get. Long. Array. Elements Get. Float. Array. Elements Get. Double. Array. Elements Get. Object. Array. Elements Array Type boolean byte short int long float double object

Functions for releasing arrays Function Array Type Release. Boolean. Array. Elements Release. Byte. Array.

Functions for releasing arrays Function Array Type Release. Boolean. Array. Elements Release. Byte. Array. Elements Release. Short. Array. Elements Relase. Int. Array. Elements Release. Long. Array. Elements Release. Float. Array. Elements Release. Double. Array. Elements Release. Object. Array. Elements boolean byte short int long float double object

Calling java methods • What if you pass a java object to a C

Calling java methods • What if you pass a java object to a C routine and wish to “call back” a method on the Java object. • Good to avoid this when you can but sometimes it is very important. • Need to use the jobject reference that is passed in by java.

Steps to follow • Native method calls JNI function Get. Object. Class – returns

Steps to follow • Native method calls JNI function Get. Object. Class – returns the jclass object that is type of that obj • Native method calls JNI function Get. Method. ID – returns jmethod. ID of method in class (0 for no such method) • Finally, native method calls JNI function Call. Void. Method. – invokes an instance of method with void return type. You pass object, method. ID, and actual arguments.

A simple alternative – spawning a system executable • Advantages – Infinitely simpler –

A simple alternative – spawning a system executable • Advantages – Infinitely simpler – Portable – Can use any native language • Disadvantages – Can only pass data to and from vi stdout – Must reload executable for each invocation

Spawning Executable -- technique • Process p = Runtime. exec(“some_exec”); • Use p to

Spawning Executable -- technique • Process p = Runtime. exec(“some_exec”); • Use p to manage process: – p. get. Input. Stream(); – p. get. Output. Stream(); – p. kill(); – p. halt();

Legacy Collections • java. util. Vector – Still useable, but typically Array. List is

Legacy Collections • java. util. Vector – Still useable, but typically Array. List is preffered. – Only major difference is if you are using muliple threads • java. util. Hash. Table – Still useable, but typically Hash. Map is preferred. – Again, different if using multiple threads.