JNI (Java Native Interface) Invocar una función en C desde Java Linux

Explicaremos lo mas breve posible la configuracion e instalacion invocando una funcion en C desde Java en este caso lo aremos con el sistema operativo Linux, el famoso Hola mundo bueno; empezemos con la explicacion:

  • Primeramente Verificamos la version de Java que tenemos instalado
  • @kali:~$ java -version
    java version "1.6.0_34"
  • Posteriormente creamos nuestra clase Java
  • public class HolaMundo {
           
            public HolaMundo(){
              System.out.println("\n Iniciando el constructor ...");       
            }
           
            public void FuncionSimple(String str){
                   
                    System.out.println("Funcion Simple ="+ str);
            }
           
            public static void FuncionEstatica(String str){
                    System.out.println("Iniciando una funcion metodo statico="+str);
            }
           
           
            public static void main(String[] args) {
                    HolaMundo obj =new HolaMundo();
                    obj.sampleFunc("Hola Bienvenido Invocando Funcion de C desde Java");
                    System.out.println("\n Llamando una funcion....");
                   
            }

    }

  • Compilamos la clase Java HolaMundo
  • javac HolaMundo.java
  • Creamos el Header de C
  • javah HolaMundo

    Para mostrar el header construido con los metodos que se generaron agregamos estos comandos en consola

    javap -s -p HolaMundo

    y nos mostrara lo siguiente.

    Compiled from "HolaMundo.java"
    public class HolaMundo {
      public HolaMundo();
        Signature: ()V

      private void FuncionSimple(java.lang.String);
        Signature: (Ljava/lang/String;)V

      public static void FuncionStatica(java.lang.String);
        Signature: (Ljava/lang/String;)V

      public static void main(java.lang.String[]);
        Signature: ([Ljava/lang/String;)V
    }

  • Creamos la Clase HolaMundo.C
  • #include <stdio.h>
    #include <jni.h>
    #include "HolaMundo.h"//hearder creado en C
    #include <string.h>

    JNIEnv* create_vm(JavaVM ** jvm){
    JNIEnv *env;
    JavaVMInitArgs vm_args;
    JavaVMOption options;
    options.optionString = "-Djava.class.path=/home/joseguru/Desktop/JNI"; //Ruta donde se encuentran las clases
    vm_args.version = JNI_VERSION_1_6; //JDK version. Indica la version del JDK
    vm_args.nOptions = 1;
    vm_args.options = &options;
    vm_args.ignoreUnrecognized = 0;

    int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);

      if(ret < 0)

         printf("\nNo lanzara JVM\n");      

      return env;

    }

    int main(void){

    JNIEnv *env;
    JavaVM *jvm;
    jmethodID mainMethod = NULL;
    jmethodID smfnMethod = NULL;
    jclass clsJava=NULL;
    jstring StringArg=NULL;

    env = create_vm(&jvm);

    if (env == NULL)

    {

       printf("\nNo se puede crear el ambiente");

       return 1;

    }
    clsJava = (*env)->FindClass(env,"HolaMundo");

    if (clsJava != NULL)

    {

            printf("\n si encontro clase solicitada\n");  

            }

            else

        {

            printf("\n No se pudo encontrar la clase solicitada\n");       

        }
    mainMethod = (*env)->GetStaticMethodID(env, clsJava, "main", "([Ljava/lang/String;)V");

    smfnMethod = (*env)->GetStaticMethodID(env, clsJava, "FuncionEstatica", "(Ljava/lang/String;)V");

    if (mainMethod != NULL)

    {

    printf("\n llamar al método Java principal");

    (*env)->CallStaticVoidMethod(env, clsJava, mainMethod, NULL);

    }

    StringArg = (*env)->NewStringUTF(env, "Argumento de C");

    if (smfnMethod != NULL)

    {

    printf("\n  llamar al método Función estática ");

    (*env)->CallStaticVoidMethod(env, clsJava, smfnMethod, StringArg);

    }

    printf("\n C Principal \n");

    return 0;

    }

  • Compilamos gcc
  • Donde:
    Nos vamos a la carpeta donde tenemos instalado el java en este caso como se muestra la ruta
    -I /usr/lib/jvm/java-6-openjdk-i386/include
    Se realiza lo mismo para el siguiente paso practicamente cuando accedemos a la primera ruta veremos la carpeta linux
    -I /usr/lib/jvm/java-6-openjdk-i386/include/linux
    Posteriormente agregamos la siguiente ruta
    -L /usr/bin/java
    y agregamos la siguiente ruta junto con la clase HolaMundo.c para compilarlo

    -L /usr/lib/jvm/java-6-openjdk-i386/jre/lib/i386/server
    HolaMundo.c -ljvm

    Finalmente el codigo final de compilacion seria el siguiente

    gcc -I /usr/lib/jvm/java-6-openjdk-i386/include
    -I /usr/lib/jvm/java-6-openjdk-i386/include/linux
    -L /usr/bin/java
    -L /usr/lib/jvm/java-6-openjdk-i386/jre/lib/i386/server
    example1.c -ljvm
  • Exportamos el path para compilar nuestra clase en C
  • export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk-i386/jre/lib/i386/server

    SI observamos en la carpeta donde tenemos nuestros archivo en C se genero un archivo a.out ese archivo generado lo compilamos para mostrar el resultado final de Invocar una función en C desde Java Linux

    /home/joseguru/Desktop/JNI/a.out


    Saludos
    joseguru /(-__-)\

    Comentarios

    Opciones de visualización de comentarios

    Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

    Es decir ...

    ¡Ah! Es decir ... invocar un programa escrito en Java desde uno escrito en C. — Sólo por curiosidad... dado que esto es para Java 6 (versión sin soporte gratuito por parte de Oracle desde hace algunos años), ¿es el mismo procedimiento con Java 8?

    Imagen de joseguru

    Respuesta

    ¡Dormitando!

    ¡Ah! ¡Gracias! ¡No me había dado cuenta! Seguro estaba dormitando. :-P

    Imagen de echan

    Afortunadamente Mr. Nutter al

    Afortunadamente Mr. Nutter al rescate rescate:

    https://github.com/jnr/jnr-ffi