Building a Java™ Native Interface (JNI) library

Technote (FAQ)
Problem
An overview of the JNI process and description of how to write and use a simple JNI library. Some of these creation details are not documented elsewhere.
Solution
Developing a JNI library involves multiple files:
  • A Java file (and its .class file) that defines a class to declare, load, and interface to the native library
  • A Native C header (.h) file that declares the native library methods
  • A Native C code(.c) file that implements the native library methods and contains the actual native code
  • A Native library file loaded by Java (.dll on Windows®, .so on AIX® and Solaris™)

The steps involved in creating a JNI library are the same for all platforms with some minor, yet significant, differences:
  1. Create a Java source (.java) file that will interface to the native library. The class must contain the following:

    1. One private method declaration for each native method in the library. Use the native keyword in each declaration and no body. These are abstract methods, the body code of which is provided by the library.

    2. One or more public methods to access the native methods

    3. A static block to load the native library file. The library can be loaded explicitly, but the static block is most common. Below is an example of NativeHello.java.
      How to specify the library name in System.loadLibrary()is explained in Step 5.

      public class NativeHello {
      static {
      System.loadLibrary( "NativeHello" );
      }
      public void hello() {
      nativehello();
      }
      private native void nativehello();
      }

  2. Compile the Java source with the javac command to produce a .class file.

    For example:javac NativeHello.java

  3. Run javah against the .class file created in Step 2. This creates a C header file (NativeHello.h). The header file declares the same native methods in C format using standard JNI syntax. For the NativeHello example above, use:

    javah -jni NativeHello

    This creates the following header file:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class NativeHello */
    #ifndef _Included_NativeHello
    #define _Included_NativeHello
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
    * Class: NativeHello
    * Method: nativehello
    * Signature: ()V
    */
    JNIEXPORT void JNICALL Java_NativeHello_nativehello(JNIEnv *, jobject);
    #ifdef __cplusplus
    }
    #endif
    #endif

  4. Create a C code file (NativeHello.c) to implement the actual native methods. Below, the Java_NativeHello_nativehello method has been implemented to write "Hello World...." to stdout. Note that this file includes the .h header file created in the previous step.

    #include "NativeHello.h"
    #include <stdio.h>
    /*
    * Class: NativeHello
    * Method: nativehello
    * Signature: ()V
    */
    JNIEXPORT void JNICALL Java_NativeHello_nativehello
    (JNIEnv * env, jobject jobj) {
    printf( "Hello World...." );
    }

  5. Compile and link the C file into a library file. The commands to compile and link are dependent upon the operating system platform. The Java method, System.loadLibrary(), requires that the library files conform to a platform-dependent naming convention.

    For Unix® (Solaris and AIX), the name must start with lib and end with .so.

    For Windows, the name must end with .dll. For our NativeHello example, the library name must be libNativeHello.so for Unix and NativeHello.dll for Windows.
    1. For AIX, an export file (NativeHello.exp) is created to declare the library's public methods, one name per line. For example:

      #! /home/sharelib/shrsub.o

      Above is the full path to share the library object file:
      Java_NativeHello_nativehello

      Then create a shell script file (mkhello.sh) with the following two commands to compile and link the library (libNativeHello.so):

      rm libNativeHello.so
      cc -I/usr/jdk_base/include -I/usr/jdk_base/include/aix -o \
      libNativeHello.so -bE:NativeHello.exp -bnoentry -bM:SRE NativeHello.c

    2. For Solaris, according to Essential JNI, the following command line compiles and links the library (libNativeHello.so):

      cc -I$JDK_HOME/include -I$JDK_HOME/include/solaris -G \
      -o libNativeHello.so NativeHello.c

    3. For Windows, using Microsoft® Visual C++® V6.0, a mkhello.bat file was created to compile and link the library (NativeHello.dll):

      set lib=d:\vc60\vc98\lib
      cl /GD /LD /Id:\vc60\vc98\include
      /Id:\WebSphere\AppServer35\jdk\include \NativeHello.c

  6. Writing and creating a JNI library module is the same, whether you access it from a command-line Java program or from a Servlet. The most common error associated with accessing a library is "java.lang.UnsatisfiedLinkError". There are two reasons for this error; either the Java virtual machine (JVM™) cannot find the library file, or a method within the library cannot be found.

    There are two key things to ensure that the JVM can locate the library file:
    1. The library file name must follow a system-dependent convention (Step 5 above).

    2. The JVM must be able to locate the library's directory. The JVM library search path is set through an environment variable:
      For AIX, the variable is called LIBPATH; each directory entry separated by a colon.
      For Solaris, the variable is called LD_LIBRARY_PATH; each directory entry separated by a colon.
      For Windows, the variable is called PATH; each directory entry separated by a semi-colon.

      In WebSphere Application Server, these environment variables can be set either from the AppServer > General > Environment window, or in the WebSphere Application Server startup script, if applicable.

      For WebSphere Application Server V3.02 on Windows, the library directory must be included in the nanny.path in the admin.config file.
    If the JVM successfully locates the library file, you might still get "java.lang.UnsatisfiedLinkError" if it cannot find a desired method in the library. This is probably caused by a name mismatch. When javah (Step 3 above) creates the header (.h) file, it "mangles" the method names to include Java class and package names. One common reason for a mismatch is when the package or class name changed since the library was last built or if the .C or .H files were not updated to match such changes.

    You can use the following Java file (TestHello.java) to test the example library from the command line:

    public class TestHello {
    public static void main( String[] args ) {
    NativeHello myhello = new NativeHello();
    myhello.hello();
    }
    }

    You can use the following Java Servlet (TestHelloServlet.java) to test the example library from WebSphere Application Server. "Hello World...." is output to the stdout.txt file.

    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.util.*;
    import java.io.*;
    public class TestHelloServlet extends HttpServlet {
    public void doGet( HttpServletRequest req,
    HttpServletResponse resp )
    throws ServletException, IOException {
    NativeHello myhello = new NativeHello();
    myhello.hello();
    PrintWriter out = resp.getWriter();
    out.println( "<HTML><BODY>" );
    out.println( "Hello written to stdout.<bR>" );
    out.println( "</BODY></HTML>" );
    }
    }


    For a comprehensive, detailed tutorial, refer to Essential JNI by Rob Gordon, published by Prentice Hall. This book gives a brief history of JNI as well as a good explanation of how and why file method names are as "mangled" as they are.











Document Information

Product categories: Software, Application Servers, Distributed Application & Web Servers, WebSphere Application Server, Servlet Engine/Web Container
Operating system(s): AIX, HPUX, Linux, Multi-Platform, Solaris, Windows
Software version: 3.5, 3.5.1, 3.5.2, 3.5.3, 3.5.4, 3.5.4.1, 3.5.4.2, 3.5.5, 3.5.6, 3.5.7, 4.0, 4.0.1, 4.0.2, 4.0.3, 4.0.4, 4.0.5, 4.0.6, 4.0.7
Software edition: Advanced, Base, Edition Independent, Network Deployment, Single Server
Reference #: 1047339
IBM Group: Software Group
Modified date: 2004-09-17