Posteado por: miguelio | septiembre 16, 2008

Hello World en JNI

Como parte de mi proyecto de conectar pics de la serie 18 de microchip con java escribí este artículo sobre como realizar un programa en java usando JNI:

Introducción 

Este documento muestra como construir un Hello World usando JNI.

JNI es la sigla de “Java Native Interface” y como su nombre lo indica, es una interfaz que permite llamar a funciones compiladas en el código nativo de la máquina en que se está ejecutando el programa.

Para esto, primero debemos escribir la función en algún lenguaje y compilarla como una librería del entorno en el que vamos a llamarla. (Por ejemplo en Windows, podemos compilar una DLL en Visual C++ con las funciones que queremos llamar desde Java).

Hello JNI World

Antes que nada, si queremos usar JNI tenemos que poder compilar un ejemplo simple y verificar como funciona:

Mundo Java

Se empieza por crear la clase Java definiendo la interfaz de comunicación con la futura DLL.

 

 

import java.util.*;


class HelloWorld {

//Native method declaration

  native void sayHello(String name);

//Load the library

  static {

    System.loadLibrary(“helloworld”);

  }


  public static void main(String args[]) {

//Create class instance

    HelloWorld hello =new HelloWorld();

//Call native method

    hello.sayHello(“Nerdy”);

  }

}

 

 

Compilar la clase con el comando “javac HelloWorld.java”

 

Luego ejecutar el comando “javah HelloWorld”. Se generará un header HelloWorld.h que contiene la descripción de los métodos que debería implementar la libería dll:

 

/* 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

/*

 * Class:     HelloWorld

 * Method:    sayHello

 * Signature: (Ljava/lang/String;)V

 */

JNIEXPORT void JNICALL Java_HelloWorld_sayHello

  (JNIEnv *, jobject, jstring);


#ifdef __cplusplus

}

#endif

#endif

 

 

Mundo C

Cómo paso siguiente vamos a implementar la función en C++ (en realidad en C, porque no vamos a crear ninguna clase) para Visual C++ de esta manera:

 

#include <jni.h>

#include “HelloWorld.h”

#include <stdio.h>


JNIEXPORT void JNICALL 

Java_HelloWorld_sayHello(JNIEnv *env, jobject obj, jstring name)

{

  jboolean iscopy;

  const char *charsname = (*env)->GetStringUTFChars(

                env, name, &iscopy);

  printf(“Hello “);

  printf(charsname);

  printf(“, this is your first JNI library\n”);

  return;

}

 

 

Algunas observaciones:

 * #include <jni.h>: Esta línea es necesaria para poder usar las funciones de JNI dentro de la DLL. JNI implementa “métodos” y constantes para comunicarse con Java, por ejemplo para convertir tipos de datos. 

 * JNIEXPORT void JNICALL: Esta línea es un ejemplo del uso de definiciones JNI para código C, indica como se exporta la función en la dll y el método de llamada a la misma. Lo único que nos importa es que tiene que ir así.

 * JNIEnv *env: Este es un puntero al objeto environment de JNI. Con los métodos de este objeto hacemos por ejemplo transformaciones de formato de los parámetros. Además es un handler al thread actual de la máquina virtual de java.

 * jobject obj : Esta es la referencia al método de Java que llama a la función. Supongo que sirve para hacer recursión. Si el método que hace la llamada es estático viene un jclass.

 * jstring: La clase String de Java no existe en C++, hay que hacer una conversión para poder usar los datos. Esto se hace en la línea const char *charsname = (*env)->GetStringUTFChars(env, name, &iscopy); donde *charsname es un puntero a un char que en realidad apunta a una cadena de caracteres (ver pointers en C) y el operador -> es como el punto “.” en Java pero para objetos referenciados por puntero (el tipo env de era JNIEnv* y por eso hay que usarlo).

 

Por último, una vez está escrito el código hay que compilar. La forma más fácil de hacer esto (si la DLL está compuesta de un único archivo .c) es compilarla directamente desde linea de comandos. Para eso hay que abrir “Simbolo de Sistema de Visual Studio”. Esto despliega una nostálgica ventana de DOS donde se puede ejecutar el comando para generar la librería. No lo hacemos con la línea de comandos común y corriente (ejecutando cmd) porque haría falta setear muchas variables de entorno de Visual Studio.

 

Lo mejor para compilar es meter el comando dentro de un archivo .bat para poder usar la variable de entorno %JAVA_HOME% que apunta al directorio del JDK. Dentro de este la carpeta include contiene el archivo “jni.h” al que se hace referencia desde el código de la DLL. Luego desde la consola de Visual Studio llamamos a nuestro script (por ejemplo makeDLL.bat).

 

El comando dentro del archivo makeDLL.bat es:

 

cl -I%JAVA_HOME%/include -I%JAVA_HOME%/include/win32 -LD HelloWorld.c -Fehelloworld.dll

 

La opción -I incluye al directorio para buscar los includes, -LD indica el archivo fuente con el que creará una DLL y por último -Fe indica el nombre del archivo de salida.

Esto generará el archivo HelloWorld.dll y sus correspondientes HelloWorld.obj y HelloWorld.lib que no nos sirven para nada y se pueden borrar.

 

Finalmente, para probar el programa ejecutamos “java HelloWorld” y obtenemos la siguiente salida:

 

Hello Nerdy, this is your first JNI library

 

Conclusión

A esta altura creo que se habrán dado cuenta de que JNI no es fácil. No es algo trivial (sobre todo si piensan en objetos complejos y threads). 

Este fue uno de los HelloWorld más complicados que ví en mi vida. Por suerte hay bastante buena documentación en Internet:

 * Introductoria: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jni.html de acá saqué en parte las cosas para hacer el HelloWorld

 * Más completo: Java Native Interface: Programmer’s Guide and Specification. Se puede bajar el libro en html o pdf o verlo en línea.

 * Especificación completa: http://java.sun.com/javase/6/docs/technotes/guides/jni/index.html.

Anuncios

Responses

  1. Saludos. Me interesaría saber más sobre tu proyecto de utilizar JNI para conectar pics de la seri 18, dado que estoy en un proyecto similar. En donde puedo informarme sobre tu proyecto? o bien, si es posible que puedas ayudarme sobre este asunto?

    • Andres me gustaria ponerme en contacto contigo, para hablar sobre algun apartado de tu tesis del medidor de estrés. mi mail es guilleloma(arroba)gmail.com


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Categorías

A %d blogueros les gusta esto: