Mit JNA können in C geschriebene dynamische Bibliotheken von Java aus aufgerufen werden. JNA kapselt die JNI (Java Native Interface und vereinfacht ihren Gebrauch. Prinzipiell besteht der Unterschied darin, dass JNI die Datenkonversion auf der C-Ebene durchführt, während JNA dies auf Java-Seite übernimmt.
Download der JNA JAR-Datei
Für die Arbeit mit der JNA muss eine JAR eingebunden werden, die auf der
Website
https://github.com/twall/jna/#download
heruntergeladen werden kann.
Im Listing müssen die entsprechenden Klassen importiert werden.
// Das Interface stellt C-Funktionen am Beispiel der Standardfunktion puts zur Verfügung import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; public interface MeinInterface extends Library { // Windows will wieder Sonderwurst beim Namen der Standardbibliothek String libName = Platform.isWindows() ? "msvcrt" : "c"; MeinInterface INSTANCE = (MeinInterface) Native.loadLibrary(libName, MeinInterface.class); // Es folgen die aufrufbaren C-Funktionen der Bibliothek void puts(String s); }Dieses Interface wird im folgenden Beispiel aufgerufen.
// Die Funktion puts wird gerufen. public class MeinCaller { public static void main(String[] args) { MeinInterface.INSTANCE.puts("Hello, World"); } }
Einbinden der JAR-Datei
Kommandozeile
Bei der Übersetzung muss die jar-Datei für JNA eingebunden werden. Bei den IDEs wird die jar-Datei als Bibliothek dem Projekt hinzugefügt. Bei Übersetzung über den Befehl javac muss diese per Option -classpath hinzugefügt werden.javac -classpath jna-4.1.0.jar MeinInterface.java javac -classpath .:jna-4.1.0.jar MeinCaller.javaAusgeführt wird mit der Option -cp
java -cp .:jna-4.1.0.jar MeinCallerUnter Windows muss als Trennzeichen ein Semikolon statt eines Doppelpunkts angegeben werden.
NetBeans
Bei NetBeans wird die JAR-Datei dem Projekt hinzugefügt. Dazu klickt man das Projekt mit der rechten Maustaste an und folgt den Menüeinträgen bzw. Buttons:Project-Properties | Libraries | Add JAR/FolderDann fügt man die heruntergeladene jna.jar ein. Es beginnt automatisch das Background Scanning des Projekts.
Die eigene C/C++-Bibliothek
Nun soll eine eigene C/C++-Bibliothek aufgerufen werden. Spätestens wenn auch von C/C++ aus Java-Methoden aufgerufen werden sollen, ist ein Umstieg zu JNI (Java Native Interface erforderlich.Um eine eigene C-Funktion aufzurufen, muss diese als dynamische Bibliothek vorliegen. Prinzipiell kann die Bibliothek auch in C++ geschrieben sein, nur die Schnittstelle muss C sein, weil sowohl UNIX/Linux als auch Windows nur C-Schnittstellen bei dynamischen Bibliotheken verwenden.
Die Vorgehensweise wird anhand der einfacheren Variante unter Linux gezeigt. Die Windows-Version wird an anderer Stelle im Zusammenhang mit dynamischen Bibliotheken unter C++ ausgeführt.
Wir programmieren eine Bibliothek libhello. Unter Linux muss eine dynamische Library immer mit lib anfangen. Beim Einbinden des Bibliothek wird aber nur noch der Name hinter lib genannt, im Beispiel also hello.
#includeMan sieht hier deutlich, dass es sich um C++-Code handelt. Nur die externe Schnittstelle wird als "C" markiert. Übersetzt wird die Bibliothek so:using namespace std; extern "C" { // damit der Zugriff von JNA klappt void sagHallo() { cout << "Hallo" << endl; } }
cc -c libhello.cpp cc -shared -o libhello.so libhello.oDie fertige Bibliothek wird mit root-Rechten in ein Verzeichnis geschoben, in dem dynamische Bibliotheken gesucht werden. Das ist beispielsweise /usr/lib.
sudo cp libhello.so /usr/libDas Interface muss auf die Bibliothek hello und die Funktion sagHallo angepasst werden.
import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; public interface LibHelloInterface extends Library { String libName = "hello"; LibHelloInterface INSTANCE = (LibHelloInterface) Native.loadLibrary(libName, LibHelloInterface.class); // Es folgen die aufrufbaren C-Funktionen der Bibliothek void sagHallo(); }Der Aufrufer ruft sagHello über das Interface LibHelloInterface.
public class LibHelloCaller { public static void main(String[] args) { LibHelloInterface.INSTANCE.sagHallo(); } }Beides muss übersetzt werden und kann dann gestartet werden.
javac -classpath jna-4.1.0.jar LibHelloInterface.java javac -classpath .:jna-4.1.0.jar LibHelloCaller.java java -cp .:jna-4.1.0.jar LibHelloCaller