Développer en Java/Faire appel à du code natif

Un livre de Wikilivres.

Java est capable d'utiliser du code natif pour réaliser certaines fonctions spécifiques à un système d'exploitation (en général des fonctions de bas niveau telle que la gestion des utilisateurs, ...). Une partie de l'API Java a recourt à du code natif (accès aux fichiers, interface graphique).

Les applications Java peuvent également faire appel à du code natif pour étendre les possibilités de l'application, ou pour améliorer les performances de l'application. L'inconvénient majeur est que cela amoindrie la portabilité de celle-ci.

Principes[modifier | modifier le wikicode]

L'appel au code natif depuis Java se fait avec l'API JNI (Java Native Interface).

Côté Java[modifier | modifier le wikicode]

L'application Java peut faire appel à des méthodes déclarées avec le mot-clé native et ne comportant pas de corps d'implémentation (comme les méthodes abstraites) car le code natif est dans un fichier séparé.

Côté code natif[modifier | modifier le wikicode]

Le code natif doit fournir l'implémentation des méthodes déclarées comme native dans les classes Java. En théorie, il peut utiliser n'importe quel langage de programmation.

En pratique, le C et le C++ sont les plus utilisés. De plus le JDK fournit l'outil javah pour générer un fichier d'en-tête (*.h) à partir d'une classe Java compilée (*.class). Ce fichier d'en-tête contient une déclaration pour chaque méthode déclarée avec le mot clé native. Il faut ensuite créer un projet de type DLL et implémenter les fonctions du fichier d'en-tête généré.

Le résultat de la compilation est une librairie de fonctions qui doit être accessible depuis l'application Java. Sous Windows, il s'agit d'une Dynamically Linked Library (*.dll). Sous Linux, il s'agit d'un Shared Object (*.so).

Lien Java-Code natif[modifier | modifier le wikicode]

Le lien est assuré par le code Java qui doit utiliser la méthode statique System.loadLibrary(String name). Celle-ci a pour paramètre le nom de la librairie de code natif à charger en mémoire.

La librairie implémentant une méthode native doit impérativement être chargée avant l'appel à la méthode. Elle doit être située dans l'un des chemins listés par la propriété java.library.path. Si la librairie nommée n'est pas trouvée, une exception java.lang.UnsatisfiedLinkError est lancée.

Comme la librairie doit être chargée avant toute utilisation de la classe, le chargement est généralement fait dans le bloc d'initialisation statique de la classe.

Portabilité[modifier | modifier le wikicode]

Le nom de la librairie fourni à la méthode statique System.loadLibrary(String name) ne dépend pas du système d'exploitation car la JVM se charge de transformer le nom de librairie en nom de fichier. Pour une librairie nommée test, le fichier chargé par la JVM sera :

  • test.dll sous Windows,
  • libtest.so sous Linux.

Pour qu'une application utilisant du code natif puisse s'exécuter sur différentes plateformes, il faut fournir une librairie pour chacune d'entre elle.

Étapes[modifier | modifier le wikicode]

Le développement d'application appelant du code natif se déroule en général de la façon suivante :

  1. Délimiter ce qui sera développé en Java, et en code natif (le minimum en général),
  2. Créer la classe Java déclarant les méthodes natives, et chargeant la librairie native,
  3. La compiler,
  4. Générer le fichier d'en-tête (*.h) grâce à l'outil javah du JDK,
  5. Créer un nouveau projet C ou C++ intégrant le fichier d'en-tête généré,
  6. Implémenter les méthodes du fichier d'en-tête,
  7. Compiler la librairie, et la placer au bon endroit pour y accéder depuis Java,
  8. Tester et déboguer.