Invocando Métodos Java desde Código Nativo con JNI

La Interfaz Nativa de Java (JNI) permite que el código escrito en lenguajes como C o C++ innteractúe con aplicaciones Java. Una de las funcionalidades clave de JNI es la capaciadd de llamar a métodos definidos en el lado de Java desde el código nativo.

Acceso a Constructores Java

Para invocar un constructor de Java desde C/C++:


JNIEXPORT jobject JNICALL Java_JniMain_invocarConstructor(JNIEnv * env, jobject jobj) {
   // 1. Localizar la clase Java especificada.
   jclass claseFecha = (*env)->FindClass(env, "java/util/Date");

   // 2. Obtener el ID del método constructor.
   // "<init>" es el nombre reservado para constructores.
   // "()V" es la firma del método (constructor sin argumentos que retorna void).
   jmethodID constructorId = (*env)->GetMethodID(env, claseFecha, "<init>", "()V");

   // 3. Crear una nueva instancia del objeto Date.
   // NewObject devuelve un jobject que representa la instancia creada.
   jobject objetoFecha = (*env)->NewObject(env, claseFecha, constructorId);

   // 4. Obtener el ID del método getTime de la clase Date.
   jmethodID metodoGetTimeId = (*env)->GetMethodID(env, claseFecha, "getTime", "()J");

   // 5. Ejecutar el método getTime en la instancia creada.
   jlong tiempoActual = (*env)->CallLongMethod(env, objetoFecha, metodoGetTimeId);

   printf("Tiempo actual: %lld\n", tiempoActual);
   return objetoFecha;
}
   </init></init>

Invocación de Métodos de Instancia Java

Para llamar a métodos no estáticos definidos en una clase Java:

Clase Java de ejemplo:


public class JniMain {
   public native void invocarMetodoInstancia();

   public int obtenerNumeroAleatorio(int limite) {
       return new Random().nextInt(limite);
   }
}
   

Código nativo C/C++:


JNIEXPORT void JNICALL Java_JniMain_invocarMetodoInstancia(JNIEnv *env, jobject objInstancia) {
   // 1. Obtener la referencia a la clase del objeto Java.
   jclass claseJniMain = (*env)->GetObjectClass(env, objInstancia);

   // 2. Obtener el ID del método a invocar.
   // "obtenerNumeroAleatorio" es el nombre del método.
   // "(I)I" es la firma del método (recibe un int, retorna un int).
   jmethodID metodoRandomId = (*env)->GetMethodID(env, claseJniMain, "obtenerNumeroAleatorio", "(I)I");

   // 3. Invocar el método de instancia.
   // Se pasa la instancia del objeto Java (objInstancia) y el argumento (200).
   jint numeroAleatorio = (*env)->CallIntMethod(env, objInstancia, metodoRandomId, 200);

   printf("Número aleatorio recibido desde Java: %d\n", numeroAleatorio);
}
   

Llamada a Métodos Estáticos Java

Para ejecutar métodos declarados como static en Java desde código nativo:

Clase Java de ejemplo:


import java.util.UUID;

public class JniMain {
   public native void invocarMetodoEstatico();

   public static String obtenerUUIDUnico() {
       return UUID.randomUUID().toString();
   }
}
   

Código nativo C/C++:


#include &ltstdio.h&gt
#include &ltstdlib.h&gt // Para sprintf
#include &ltjni.h&gt

JNIEXPORT void JNICALL Java_JniMain_invocarMetodoEstatico(JNIEnv *env, jobject objInstancia) {
     // 1. Obtener la referencia a la clase Java.
     // Se utiliza GetObjectClass para obtener la clase del objeto proporcionado.
     jclass claseJniMain = (*env)->GetObjectClass(env, objInstancia);

     // 2. Localizar el ID del método estático.
     // "obtenerUUIDUnico" es el nombre del método estático.
     // "()Ljava/lang/String;" es la firma (no recibe argumentos, retorna un String).
     jmethodID metodoUUIDId = (*env)->GetStaticMethodID(env, claseJniMain, "obtenerUUIDUnico", "()Ljava/lang/String;");

     // 3. Invocar el método estático.
     // Se pasa la clase directamente, no una instancia.
     jstring uuidJava = (*env)->CallStaticObjectMethod(env, claseJniMain, metodoUUIDId);

     // Convertir el jstring de Java a una cadena C (char*).
     const char *uuidC = (*env)->GetStringUTFChars(env, uuidJava, NULL);
     if (uuidC == NULL) {
         // Manejar error si no se pudo obtener la cadena
         return;
     }

     // Crear un nombre de archivo dinámico y escribir en él.
     char nombreArchivo[200];
     sprintf(nombreArchivo, "D:/%s.txt", uuidC); // Ejemplo de ruta, puede requerir ajustes
     FILE *archivo = fopen(nombreArchivo, "w");
     if (archivo == NULL) {
         // Liberar la cadena C antes de retornar si fopen falla
         (*env)->ReleaseStringUTFChars(env, uuidJava, uuidC);
         printf("Error al abrir el archivo.\n");
         return;
     }
     fputs("Contenido de ejemplo escrito desde C++.", archivo);
     fclose(archivo);
 
     printf("Archivo '%s' escrito exitosamente.\n", nombreArchivo);

     // Liberar la memoria de la cadena C obtenida de jstring.
     (*env)->ReleaseStringUTFChars(env, uuidJava, uuidC);
}
   

Etiquetas: JNI java C C++ métodos nativos

Publicado el 7-22 10:52