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 <stdio.h>
#include <stdlib.h> // Para sprintf
#include <jni.h>
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);
}