# Presentation: 890756

## Java TrainingIntroduction to JNI

- Written by Jeff Smith

## What is JNI? -1

- JNI stands for Java Native Interface
- JNI specifies a communication protocol between Java code and external, native code.
- It enables your Java code to interface with native code written in other languages (such as C, C++)
- Native code typically accesses the CPU and registers directly and is thus faster than interpreted code (like Java)
- Java native methods are methods declared in your Java code (much like you declare an abstract method), but which are actually implemented in another programming language

## What is JNI? -2

- JNI allows Java programmers to
- Leverage platform specific features outside a JVM. For example, you typically can't write a device driver in Java because you can't directly access the hardware
- Leverage the improved speed possible with natively compiled code (such as C or assembler). For example, you might need an extremely fast math routine for a scientific application or game program.
- Utilize existing code libraries in your Java programs. For example, there might be a really good file compression library written in C. Why try to rewrite it in Java when you can access it (as is) using JNI?

## What is JNI? -3

- JNI Drawbacks
- Your program is no longer platform independent
- Your program is not as robust. If there is a null pointer exception in your native code, the JVM can't display a helpful message. It might even lock up.

## What is JNI? -4

- JNI supports
- Native methods can create and manipulate Java objects such as strings and arrays.
- Native methods can manipulate and update Java objects passed into them (as parameters)
- You can catch and throw exceptions from native methods and handle these exceptions in either the native method or your Java application
- This almost seamless sharing of objects makes it very easy to incorporate native methods in your Java code

## Writing JNI Methods -1

- You write JNI programs for C/C++ by doing the following
- Create a Java class that declares the native method, contains code for loading the native library. The class should also contain a main method which calls the native method
- Compile the Java class
- Run the javah tool with the -jni option to generate a header file for your native C/C++ code
- Write the C/C++ code (file) which implements the method defined in the header file
- Compile the header and C/C++ code into a library (a DLL under Windows)
- Run the Java class (main method)

## Writing JNI Methods -2

- 1. Write Your Java class**package com.cexp.wms.jni.examples;****class HelloWorld ****{ ****  public native void displayHello(); ****//native method**** ****  static   ****//static initializer code****  ****  { ****     System.loadLibrary("c_library"); ****  } ****  public static void main(String[] args) ****  { ****    HelloWorld hw = new HelloWorld();**
**         ****hw.displayHello(); ****  } ****} **

## Writing JNI Methods -3

- 2. Compile your class**javac HelloWorld.java**

## Writing JNI Methods -4

- 3. Create the header (.h) file by using the javah tool**javah -jni -o HelloWorld.h -classpath . com.cexp.jni.examples.HelloWorld**
- (Note: entire command must be on one line)
- This command will create a file called HelloWorld.h
- which contains a C function signature for implementing
- the native method.
- The C header file will include <jni.h>, the standard header file
- for JNI applications.

## Writing JNI Methods -5

- 3. The header file it creates will look something like
**/* DO NOT EDIT THIS FILE - it is machine generated */**
**#include <jni.h>**
**/* Header for class HelloWorld */**
**#ifndef _Included_HelloWorld**
**#define _Included_HelloWorld**
**#ifdef __cplusplus extern "C" {**
**#endif**
**JNIEXPORT void JNICALL**
**Java_com_cexp_wms_jni_examples_HelloWorld_displayHello**
**  ****(JNIEnv *, jobject);**
**#ifdef __cplusplus**
**}**
**#endif**
**#endif**

## Writing JNI Methods -6

- The displayHello routine has two parameters (standard for all JNI native methods).
- JNI Env *  -- JNI interface pointer. We can use this pointer to make useful calls like GetStringUTFChars(), which allows us to convert Java Unicode (2 byte) strings to UTF-8 (1 byte) strings.
- jobject -- A reference to the (calling) object itself. Similar to ***this***
- If we passed in our own parameter, it would start after these two parameters (it would be the *third* parameter)

## Writing JNI Methods -7

- JNI native methods can access the following types
**boolean  jboolean**
**string   jstring**
**byte     jbyte**
**char     jchar**
**short    jshort**
**int      jint**
**long     jlong**
**float    jfloat**
**double   jdouble**
**void     void**** **
- JNI_TRUE and JNI_FALSE are also defined

## Writing JNI Methods -8

- All of these types can be accessed directly except for jstring, which requires a subroutine call to in order to convert a Java Unicode string (2 bytes) to a C-style char* string (1 byte UTF-8 format).
- To convert a jstring to a C-style string, you might write code like the following:
**JNIEXPORT void JNICALLJava_MyJavaClass_printName(JNIEnv *env, jobject obj, jstring name)**
**{    **
** ****const char *str= (*env)->GetStringUTFChars(env,name,0);    **
** ****printf(“%s”, str);      **
**  ****//need to release this string when done with it in**
**  ****//order to avoid memory leak    **
** ****(*env)->ReleaseStringUTFChars(env, name, str);**
**}**** **

## Writing JNI Methods -9

- You can use the (*env)->NewStringUTF() function to create a new jstring from a C-style string. For example, a C function that needs to return a Java string could contain the following code:
**JNIEXPORT jstring JNICALLJava_MyJavaClass_getName(JNIEnv *env, jobject obj)**
**{****   **
**  ****return (*env)->NewStringUTF(env, “Fred Flintstone”);**
**}**** **

## Writing JNI Methods -10

- 4. Write the native C/C++ code which implements the method. Use the same signature that your header file uses. You might name your file something like "HelloWorld.c".
**#include <jni.h>**
**#include "HelloWorld.h" **
**#include <stdio.h> **
**JNIEXPORT void JNICALL**
**Java_com_cexp_wms_jni_examples_HelloWorld_displayHello (JNIEnv *env, jobject obj) **
**{ **
**  ****printf("Hello world! I'm here! \n"); **
**  ****return; **
**} **

## Writing JNI Methods -11

- 5. Compile the C/C++ code into a library (a DLL if your code will run under Windows).
- If you use C++ Builder to compile your library under Windows,
- make sure you create a DLL project and then add the C/C++
- file to it (e.g. HelloWorld.c). You'll need to add the following to
- your compiler's include path:
-     \javadir\include
-     \javadir\include\win32
- Be sure to name your project c_library so the DLL it creates will
- be named c_library.dll.

## Writing JNI Methods -12

- 5. If you are compiling your C library under Windows using Visual C++, you do the following:
**cl -Ic:\javadir\include -Ic:\javadir\include\win32 **
**-LD HelloWorld.c -Fec_library.dll**
- (Note: entire command must be on one line)
- This creates the file, c_library.dll

## Writing JNI Methods -13

- 5. If you are compiling your C library under Solaris, you do the following:
**cc -G -I/javadir/include -I/javadir/include/solaris \ HelloWorld.c -o c_library.so **
- This creates the file, c_library.so

## Writing JNI Methods -14

- 6. Run the Java class (main method). Switch to the directory just above the "com" directory and run the following:
**java -classpath . com.cexp.wms.jni.examples.HelloWorld**
- You should see "Hello world! I'm here!" appear on the screen!
- If you see a "java.lang.UnsatisfiedLinkError" error message,
- then Java couldn't find your shared library. Either add the
- directory your library (DLL) resides in to your Java runtime
- library path **OR** copy the library file to the working directory of
- your Java program.

## JNI and Fortran

- You can invoke Fortran code from your Java applications
- To do that, you write some Java JNI code to invoke C/C++ methods in a DLL, and write those C/C++ methods to invoke the Fortran code you want to run
- It sounds complicated, but the runtime overhead isn’t as bad as you might think

- JNI
- (Java program)

- C/C++ “bridge”
- DLL

- Fortran program

## JNI Summary

- JNI can be a little tedious the first time you try it, but in the scheme of things it isn't that complicated.
- Use JNI to
- leverage existing code (that you don't want to port to Java)
- Solve problems that Java isn't suited for (e.g., when you need the speed of C or assembler, or when you need to write low level code to communicate directly with hardware
- Learn more about JNI at:
- http://java.sun.com/docs/books/tutorial/native1.1/index.html
- http://www.javaworld.com/javatips/jw-javatip141.html
- (article I wrote for Java World back in 2003)

## JNI Exercise

- Background: JDK 1.3's math package was very fast. JDK 1.4 uses a new StrictMath library which is much slower for certain functions like sin() and cos().
- Create a C library (DLL) that will do fast sin() and cos() functions.
- Integrate this library into a Java class via JNI and run benchmarks comparing the speed to the native Java sin() and cos() methods.
- Is it faster?