Neuigkeiten

JNI mal andersherum – Java Applikationen direkt in C++ Applikation einbinden.
Geschrieben am 30. Juli 2014

JNI mal andersherum – Java Applikationen direkt in C++ Applikation einbinden. Die Vorteile von Java in einer nativen Legacy-Umgebung nutzen? Das ist möglich mit Hilfe des Java Native Interface. Das JNI bietet umfangreiche Methoden um die Java Virtual Machine zu steuern und Java-Objekte in einer C++ Umgebung zu verwenden.

Aufgabenstellung

Es sollte eine bestehende Java-Applikation mit einer umfangreichen und komplexen Objektschnittstelle von einer C++-Applikation aus benutzt werden. Es war also ein Interface gefordert, das die Java-Funktionen und -Objekte über eine Proxy-Schnittstelle auf C++-Objekte abbildet. Besondere Aufmerksamkeit verlangten die Anforderungen bzgl. Speichermanagement, Exceptionhandling, Event-Handling (Callback) und Plattformunabhängigkeit. Die Interface-Implementierung sollte die Performance des Systems nicht deutlich verschlechtern. Die Integrität des Interfaces sollte durch umfangreiche, automatisierte Tests sichergestellt werden.

Anforderungen in einem Referenzprojekt

  • Komplexe Java-Applikation (ca. 400 Klassen, über 1200 Methoden)
  • Sehr umfangreiche, komplexe Funktionalität
  • Komplexe Datenstrukturen (Abbildung der Java-Typen durch native JNI-Typen oder allgemeine Java-Typen auf C++-Klassen)
  • Behandlung von Java Exceptions
  • Behandlung von Java-Events (Callbacks)
  • Plattformunabhängig (Verwendung von Boost-Bibliotheken)
  • Realisierte Plattformen: Windows x86/x64, Linux x86/x64
  • Test mit der Boost-Testsuite (über 50 teils sehr umfangreiche Testfälle)
  • Lösungsaspekte

Die Datentypen der Objekte in der C++-Applikation müssen auf die Java-Datentypen abgebildet werden. Im Fall der meisten Basistypen (z.B. integer, string, …) bietet das JNI entsprechende Typen (jint, jstring, …), mit denen die Zuordnung relativ einfach ist. Die Java-Objekte werden direkt über eine Java-Signatur definiert. Wo das JNI solche Basistypen nicht anbietet, muss mit Hilfskonstrukten gearbeitet werden, z.B. ein C++-Objekt vom Typ 64 Bit unsigned integer. Auf Java-Seite kann hier mit einem BigInteger-Objekt gearbeitet werden, das Lesen und Schreiben des Java-Objekts erfolgt mit Methoden der BigInteger-Klasse in Hilfsmethoden des Interfaces.

Um dem Java-Garbage-Collector zu erlauben, die im Interface verwendeten Java-Objekte aufzuräumen, müssen alle Referenzen auf Java-Objekte nach Verwendung wieder frei gegeben werden. Dies wurde für Klassenobjekte in aller Regel im Destruktor der Basisklasse realisiert. Temporäre Java-Objekte werden direkt nach ihrem Gebrauch freigegeben.

Events auf Java-Seite wurden als direkte Callbacks in die C++-Applikation realisiert. Der C++-Client stellt Methoden für die Eventbehandlung zur Verfügung. Die Verbindung zur Java-Seite erfolgt über die Registrierung der nativen (C++) Methoden, zusammen mit den korrespondierenden Java-Methoden und deren Parameter- und Rückgabetypen.