07 noviembre, 2006

JNI - Invocar Funciones C desde programas Java

Java Native Interface (JNI) es la mecánica propuesta por Java para invocar funciones implementadas en lenguaje C desde programas Java.

Los ejemplos que explicaremos en este capítulo fueron compilados con Microsoft VC++ (incluido en Microsoft Visual Studio Express 8)


Configuración del Entorno

Antes de comenzar con JNI vamos a asegurarnos de tener correctamente configurado el entorno de compilación Java y C. Todos los ejemplos los desarrollaremos en línea de comandos por lo tanto será necesario setear algunas variables de entorno del sistema operativo.

Variable JAVA_HOME

Esta variable generalmente se utiliza para indicar cual es el directorio de instalación del JDK (compilador Java).

set JAVA_HOME=C:\java\JDK1.5.0

Variable PATH

Debemos setear correctamente la variable PATH para asegurarnos que podremos invocar desde línea de comandos los compiladores Java y C y el runtime de Java.

set PATH=%JAVA_HOME%\bin;C:\Archivos de programa\Microsoft Visual Studio 8\VC\bin;%PATH%

Para probar que todo funciona correctamente ejecutemos el comando javac.



Ahora probemos el correcto funcionamiento del compilador C. Ejecutemos el comando cl



Variable INCLUDE

La variable include le indica al compilador C los directorios en donde debe buscar los archivos .h. Para trabajar con JNI tenemos que agregarle a esta variable los directorios %JAVA_HOME%\include y %JAVA_HOME%\include\win32

set INCLUDE=C:\Archivos de programa\Microsoft Visual Studio 8\VC\include;%JAVA_HOME%\include;%JAVA_HOME%\include\win32

Variable LIB

set LIB=C:\Archivos de programa\Microsoft Visual Studio 8\VC\lib


Comenzando...

Ahora si, podemos comenzar con nuestro HolaMundoJNI.

Para resumir lo que veremos a continuación diremos que hay 4 partes involucradas en este programa:
  • El código Java - HolaMundoJNI.java
  • El header que define la función C - HolaMundoJNI.h
  • El código C - HolaMundoJNIimpl.c
  • La librería dinámica - libreria.dll

HolaMundoJNI.java

Esta clase tendrá un método nativo. Es decir: un método definido en la clase cuya implementación será escrita en lenguaje C.

HolaMundoJNI.java


Para poder correr esta clase será necesario levantar una dll en la cual esté disponible la función C que implementa nuestro método nativo. Esto lo hacemos con la llamada:
static{ System.loadLibrary("libreria"); }


HolaMundoJNI.h

El JDK provee el comando javah. Con este comando vamos a generar el encabezado que debe tener la función C que resuelva la implementación del método nativo.



En la imagen vemos lo siguiente:

Primero compilamos la clase HolaMundoJNI.java con el comando javac (javac HolaMundoJNI.java). Luego con dir verificamos que se generó el .class (HolaMundoJNI.class).

A continuación generamos el .h que vamos a necesitar para incluir en el código c. Esto lo hacemos con el comando javah (javah -jni HolaMundoJNI). Luego verificamos que se generó el archivo HolaMundoJNI.h.

Veamos el archivo que se generó con el comando javah.

HolaMundoJNI.h



HolaMundoJNIimpl.c

La función para implementar el método nativo tiene que tener el prototipo definido en el archivo .h. Así que copiamos ese prototipo y programamos la función.

HolaMundoJNIimpl.c



Ahora podemos correr nuestro HolaMundoJNI




Pasaje de Parámetros y Valor de retorno de la Función C

Definamos un nuevo método en la clase HolaMundoJNI:
  • public native String getCustomHolaMundo(String nombre);
Este método recibe un parámetro String y tiene como valor de retorno un String.

Volvemos a correr el javah y obtenemos el siguiente prototipo:

HolaMundoJNI.h


Ahora veamos como resolvemos la función C

HolaMundoJNIimpl.c


Veamos ahora como en la clase HolaMundoJNI.java invocamos el método.

HolaMundoJNI.java


Referencias:
http://java.sun.com/docs/books/jni/html/jniTOC.html