A simple example of JNI

Java Native Interface (JNI) is a standard programming interface for writing Java native methods and embedding the JVM into native applications. Simply, it is a Java technology with which a Java application can call a method written with such as C, C++ and assembly.

Adopting JNI is very simple. You need two components -- a Java program, and a native library. The native library is written in other languages and compiled on corresonding platforms.

A function defined in the native library should be declared in Java code as a 'native' function. And the native library needs to be load in Java code with the System.loadLibrary method. The natvie function could be referced by other regular functions in the Java code.

Following is an example of the Java Code.

JNIFoo.java
===========

public class JNIFoo {    
    public native String nativeFoo();    

    static {
        System.loadLibrary("foo");
    }        

    public void print () {
    String str = nativeFoo();
    System.out.println(str);
    }
    
    public static void main(String[] args) {
    (new JNIFoo()).print();
    return;
    }
}

# javac JNIFoo.java
# javah -jni JNIFoo

A file named as JNIFoo.h is created by running the above two commands. A function of 'JNIEXPORT jstring JNICALL Java_JNIFoo_nativeFoo  (JNIEnv \*, jobject)' is in the JNIFoo.h file. The function must be implemented in a source code file (e.g. a C file), and it is the actually entry to do what the funtion of natvieFoo() in Java code do.


foo.c
======

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
#include "JNIFoo.h"

JNIEXPORT jstring JNICALL Java_JNIFoo_nativeFoo (JNIEnv \*env, jobject obj)
{
  int i;
  int ds_ret;

  char\* newstring;

  jstring ret = 0;

  newstring = (char\*)malloc(30);

  if(newstring == NULL)
  {     
      return ret;
  }

  memset(newstring, 0, 30); 
 
  newstring = "foo: Test program of JNI.\\n";
  

  ret = (\*env)->NewStringUTF(env, newstring);

  free(newstring);

  return ret;
}

JNI libraries are named with the library name used in the System.loadLibrary method of your Java code with a prefix and a suffix. On different OS, the prefix and suffix might be different.

On Solaris OS, it is prefixed by 'lib' and suffixed with '.so'

# cc -Kpic -G -o libfoo.so -I/usr/java/include -I/usr/java/include/solaris foo.c -z text

On Linux OS, it is prefixed by 'lib' and suffixed with '.so'.

# gcc -shared -fpic -o libfoo.so -I/usr/java/include -I/usr/java/include/linux foo.c

On Windows OS, it is prefixed by nothing and suffixed with '.dll'.
It could be compiled with Visual Studio automatically and create a file named as foo.dll.

On Mac OS, it is prefixed by 'lib' and suffixed with '.jnilib'.

# gcc -dynamiclib -o libfoo.jnilib -I/System/Library/Frameworks/JavaVM.framework/Headers foo.c -framework JavaVM

 

To run the JNI program locally, the following command is fine:

# java -Djava.library.path=<path_of_native_lib> JNIFoo 

Comments:

Thank you for this instruction, it is really very good for newbies.

Posted by Fiona on November 28, 2007 at 01:51 PM HKT #

Thanks :)

I really hope it helps.

Posted by Li Ye on November 29, 2007 at 10:05 AM HKT #

great post abt JNI thanks

Posted by krishna on April 15, 2008 at 06:01 AM HKT #

It is a good tutorial but It got an warning message when it the foo.c was compiled.

Whenever class JNIFoo is executed, it threw an error (Platform Linux Mandriva 2007.1 kernel version 2.6.17-13mdv, java version 1.6.0_03)

[root@tests]# gcc -shared -fpic -o libfoo.so -I/usr/java/jdk1.6.0_03/include -I/usr/java/jdk1.6.0_03/include/linux/ foo.c
foo.c: In function âJava_JNIFoo_nativeFooâ:
foo.c:13: warning: incompatible implicit declaration of built-in function âmallocâ
foo.c:20: warning: incompatible implicit declaration of built-in function âmemsetâ

[root@tests]# java -Djava.library.path=/projects JNIFoo
\*\*\* glibc detected \*\*\* java: free(): invalid pointer: 0xb591f500 \*\*\*
======= Backtrace: =========
/lib/i686/libc.so.6[0xb7e8911d]
/lib/i686/libc.so.6(cfree+0x83)[0xb7e892a3]
/projects/libfoo.so(Java_JNIFoo_nativeFoo+0x7a)[0xb591f496]
[0xb5d4666e]
[0xb5d3ed77]
[0xb5d3eedd]
[0xb5d3c243]
/usr/java/jdk1.6.0_03/jre/lib/i386/client/libjvm.so[0x620bc6d]
/usr/java/jdk1.6.0_03/jre/lib/i386/client/libjvm.so[0x630a828]
/usr/java/jdk1.6.0_03/jre/lib/i386/client/libjvm.so[0x620bb00]
/usr/java/jdk1.6.0_03/jre/lib/i386/client/libjvm.so[0x6234f26]
/usr/java/jdk1.6.0_03/jre/lib/i386/client/libjvm.so[0x62265cb]
java(JavaMain+0x2c8)[0x8049b98]
/lib/i686/libpthread.so.0[0xb7f66192]
/lib/i686/libc.so.6(clone+0x5e)[0xb7eee90e]
======= Memory map: ========

How to solve this problem ?
Thank you.

Posted by Ferry Sumendap on April 25, 2008 at 03:42 AM HKT #

Hi Ferry,

[1] For the warning issue, the reason is the the head file of malloc and memset is not declared in the head of the foo.c.

[2] To fix the error, there ought to be a little change in the foo.c file when it is complied and run on Linux system. The code of
==================
newstring = "foo: Test program of JNI.\\n";
==================
in foo.c needs to be changed to
==================
char\* tmpstring = "foo: Test program of JNI.\\n";

strcpy(newstring, tmpstring);
==================

As the foo.c is changed, compile it and run JNI program again. It will work.

Posted by moonocean on April 25, 2008 at 10:15 AM HKT #

When I ran this example on Windows, it printed:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path
I had to change the load library line in the Java file to:
System.loadLibrary("libfoo");
as the library name is libfoo.dll

Posted by nbsbhat on May 05, 2008 at 11:58 AM HKT #

Hi nbsbhat,

The following line is fine if the library name is libfoo.dll.
----------------------
System.loadLibrary("libfoo");
----------------------

In the foo.c file, the line of
------------------------
ret = (\*env)->NewStringUTF(env, newstring);
------------------------

ought to be changed to

------------------------
ret = (\*env).NewStringUTF(newstring);
------------------------

Posted by moonocean on May 07, 2008 at 10:07 AM HKT #

How to do this in C++ on solaris 10?
# cc -Kpic -G -o libfoo.so -I/usr/java/include -I/usr/java/include/solaris foo.cpp -z text
"foo.cpp", line 26: Error: Pointer type needed instead of JNIEnv_.
1 Error(s) detected.
#include <algorithm>
#include <jni.h>
#include "JNIFoo.h"

JNIEXPORT jstring JNICALL Java_JNIFoo_nativeFoo (JNIEnv \*env, jobject obj)
{
int i;
int ds_ret;

char\* newstring;

jstring ret = 0;

newstring = (char\*)new char[30];

if(newstring == NULL)
{
return ret;
}

/\* ::memset(newstring, 0, 30); \*/
std::fill(newstring, newstring + 30, 0);

newstring = (char \*) "foo: Test program of JNI.\\n";

ret = (\*env)->NewStringUTF(env, newstring);

delete [] newstring;

return ret;
}

Posted by Powah Wong on August 27, 2008 at 04:54 PM HKT #

Very nice, but how can I use the "jobject obj" to caqll back into the methods of JNIFoo ????

Posted by DukeOfHyJ on July 23, 2009 at 02:12 AM HKT #

Very nice, but how can I use the "jobject obj" to call back into the methods of JNIFoo ????

Or even easier, access a public int in JNIFoo ??

Thank you

Posted by DukeOfHwyJ on July 23, 2009 at 02:57 AM HKT #

Thanks it is very helpful for me

Posted by vivek on September 05, 2010 at 01:47 PM HKT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Ye Julia Li

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today