Exécuter du code Java avec C

Méthode 1 : Arguments de commande

La méthode la plus simple consiste à se servir des arguments de commande de C et Java.

Imaginons que nous voulons ajouter deux entiers.

Code Java


public class Add {

   public static void main(String[] args) {
     try {
 System.out.print(Integer.valueOf(args[0]) + Integer.valueOf(args[1]));
     } catch (Exception e) {
 System.err.println("Arguments incorrects");
     }
   }

}

Ce code Java prend les deux arguments et les transforme en entier puis additionne.

Ensuite, on peut créer un fichier .jar.

Code C

Le programme C va simplement exécuter le fichier .jar avec les arguments grâce à la fonction system.

#include <stdlib.h>
#include <stdio.h>

void main(int argc, char **argv) {
    char cmd [100];

    /* Concatène la commande avec les arguments du programme */
    sprintf (cmd, "java -jar add.jar %s %s", argv[1], argv[2]); 

    /* Exécute la commande */ 
    system(cmd);
}

Méthode 2 : Java Native Interface (JNI)

Cette méthode est intéressante notamment si vous voulez exécuter des fonctions indépendamment du programme.

Code Java

Le programme Java va avoir trois méthodes :

  1. main : la fonction de base. Elle prend en argument un tableau de chaînes de caractères.
  2. sayHello : Elle prend en argument un nom et affiche "Bonjour, Pierre" par exemple.
  3. add : Elle prend en argument deux entiers et elle les additionne et retourne le résultat.
public class Hello {

 public static void main(String[] args) {
  System.out.println("Démarrage de l'application Java avec " + args.length + " arguments : ");
  for (String arg : args) {
   System.out.println(arg);
  }
 }

 public static void sayHello(String name) {
  System.out.println("Bonjour, " + name);
 }

 public static int add(int x, int y) {
  return x + y;
 }

}

Code C

JNI a besoin de la signature des méthodes pour les appeler.

#include <stdio.h>
#include <jni.h>

JNIEnv* create_vm() {
 JavaVM* jvm;
 JNIEnv* env;
 JavaVMInitArgs args;
 JavaVMOption options;
 
 args.version = JNI_VERSION_1_6;
 args.nOptions = 1;

 /* le chemin du dossier contenant les classes (classpath) */
 options.optionString = "-Djava.class.path=C:\\Users\\Ronan\\eclipse-workspace\\jni-test\\bin";

 args.options = &options;
 args.ignoreUnrecognized = JNI_FALSE;

 JNI_CreateJavaVM(&jvm, (void **)&env, &args);
 
 return env;
}

void invoke_class(JNIEnv* env) {
 jclass helloClass;
 jmethodID mainMethod;

 jobjectArray args;
 jstring arg0;
 jstring arg1;

 /* Construction des arguments */
 args = (*env)->NewObjectArray(env, 2, (*env)->FindClass(env, "java/lang/String"), NULL);
 arg0 = (*env)->NewStringUTF(env, "arg0");
 arg1 = (*env)->NewStringUTF(env, "arg1");
 (*env)->SetObjectArrayElement(env, args, 0, arg0);
 (*env)->SetObjectArrayElement(env, args, 1, arg1);

 jmethodID sayHelloMethod;
 /* Construction du nom */
 jstring name = (*env)->NewStringUTF(env, "Pierre");

        jmethodID addMethod;
        jint x = 2;
 jint y = 3;
 
 /* Trouve la classe Hello */
 helloClass = (*env)->FindClass(env, "Hello");

 /* Trouve la méthode main */
 mainMethod = (*env)->GetStaticMethodID(env, helloClass, "main", "([Ljava/lang/String;)V");

 /* Trouve la méthode sayHello */
 sayHelloMethod = (*env)->GetStaticMethodID(env, helloClass, "sayHello", "(Ljava/lang/String;)V");

 /* Trouve la méthode add */
 addMethod = (*env)->GetStaticMethodID(env, helloClass, "add", "(II)I");


 /* Appel de la méthode main */
 (*env)->CallStaticVoidMethod(env, helloClass, mainMethod, args);

 /* Appel de la méthode sayHello */
 (*env)->CallStaticVoidMethod(env, helloClass, sayHelloMethod, name);

 /* Appel de la méthode add et impression du résultat */
 printf("%d + %d = %d", x, y,
        (*env)->CallStaticIntMethod(env, helloClass, addMethod, x, y));

}


void main(int argc, char **argv) {
 JNIEnv* env = create_vm();
 invoke_class(env);
}

Compilation du code C

Pour compiler le code, vous allez devoir inclure le dossier include et le dossier win32 ou linux.

Il faudra ajouter aussi la librairie JVM qui se trouve dans le dossier jre/bin/server de votre JDK

De plus, il faudra ajouter une entrée à la variable PATH pour que l'exécutable trouve la librairie jvm.

Un exemple de commande de compilation avec les chemins entiers :

gcc main.c -o prog.exe -I"C:\Program Files\Java\jdk1.8.0_211\include" -I"C:\Program Files\Java\jdk1.8.0_211\include\win32" -L"C:\Program Files\Java\jdk1.8.0_211\jre\bin\server" -ljvm

Commentaires