Open Source im professionellen Einsatz
Linux-Magazin 03/2015
© racorn, 123Rf

© racorn, 123Rf

Java mit anderen Programmiersprachen mischen

Die Mischung zählt

Bei Java interessiert nicht nur die Bohne, auch die reiche Vielfalt an Bibliotheken und Frameworks hält die Sprache wach. Und wem der Sinn nach einer Melange steht – Java integriert Fremdsprachen aller Geschmacksrichtungen.

891

Weder Projektleiter noch Programmierer mixen Sprachen aus Vergnügen. Erstere fürchten Komplexität und erhöhte Ansprüche an ihr Team, Letztere tun lieber Dinge, die sie am besten beherrschen – und das ist bei den meisten genau eine Programmiersprache. Trotzdem nützt in manchem Softwareprojekt ein zweite Sprache mehr, als sie schadet:

  • Basar-Methode: Je umfangreicher die Software, desto lohnender ist es, auf bewährte Routinen zurückzugreifen – auch wenn der recycelte Code in einer anderen Sprache geschrieben ist.
  • Performance: Stehen Low-Level-Zugriffe auf Hardware- und Betriebssystem-Ressourcen an, bieten systemnahe Programmiersprachen mehr und performantere Möglichkeiten.
  • Scripting: Skripte und Skriptsprachen geben Powerusern mächtige Werkzeuge in die Hand. Das ist selbst bei komplexen Enterprise-Anwendungen auf J2EE-Basis so.
  • Integrierbarkeit: Java-Anwendungen können als Teil eines größeren Kontextes fungieren und müssen sich anpassen, beispielsweise in das Look&Feel eines Desktops.

Java ist sehr mächtig, deshalb überrascht es nicht, dass die Sprache die Integration von fremdsprachiger Software für jeden dieser Anwendungsfälle unterstützt. Die folgenden Abschnitte zeigen solche Techniken mit ihren Vor- und Nachteilen.

Ohne C geht nichts

Ein Grund für den Erfolg von Java war, dass es den Entwickler von einigen heiklen Dingen verschont, die unter C und C++ notwendig sind, insbesondere die Verwaltung von dynamischem Speicher. Trotzdem war es den Machern von Java von Anfang an klar, dass es Java in der realen Welt ohne den Zugriff auf die vielfältig vorhandenen C-Bibiliotheken schwer haben würde. Deshalb bot schon die allererste Java-Version mit dem Java Native Interface (JNI) die Möglichkeit zur Integration von C-Code.

Der Zugriff von Java nach C erfolgt über zwei Schichten (Abbildung 1). Oben steht eine dünne Java-Klasse, die nicht viel mehr tut, als die Schnittstelle zu beschreiben und per statischer Methode die nächste Schicht zu laden. Technisch ist diese zweite Schicht eine dynamische Bibliothek (»so« -Datei beziehungsweise DLL unter Windows), die die Java-Aufrufe nach C übersetzt.

Ein Beispiel aus der Praxis: In einem Projekt des Autors [1] ging es darum, die Readline-Bibliothek für Java verfügbar zu machen. Denn ein natives Java-Programm kann die Ausgabe auf Stdout nicht einfangen. Readline darf dagegen eine Zeile ausgeben, der Benutzer kann Bash-ähnlich per Tasten darin navigieren und editieren (Abbildung 2).

Abbildung 1: Der Zugriff von Java auf C-Code passiert über Schichten.
Abbildung 2: Dank Readline lässt sich die Eingabe des vorherigen Befehls einfach editieren.

Die Bibliothek ist zum Beispiel in Jython [2] im Einsatz; Jython implementiert die Sprache Python in Java. Listing 1 zeigt einen Teil der Klassendefinition. Aus Designgründen sind alle nativen Methoden »private« , zu der Methode »public String readline(String)« (Zeile 17) gibt es also die private Methode »private native String readineImpl(String)« (Zeile 34). Die Besonderheit der Klasse ist, dass sie nicht abstrakt ist und trotzdem für diese nativen Methoden nur die Schnittstelle vorgibt. Die Methode »load()« (ab Zeilen 10) lädt die native Bibliothek.

Das im JDK mitgelieferte Tool »javah« erzeugt aus dem Bytecode der Klasse die C-Headerdatei »org_gnu_readline_Readline.h« :

javah -classpath $(BUILDDIR) -jni org.gnu.readline.Readline

Einen Auszug zeigt Listing 2. Die eigentliche Implementation besteht dann darin, die übergebenen Java-Typen – etwa »jstring« zu »char*« – in ein Format zu wandeln, das die C-Bibliothek versteht. Hier lauern ein paar Fallstricke, insbesondere auf Nicht-Unicode-Systemen.

Listing 1

Ausschnitt der Klasse Readline.java

01 package org.gnu.readline;
02
03 import java.io.*;
04 import java.util.*;
05
06 public class Readline {
07
08 [...]
09
10   public static final void load(ReadlineLibrary lib) throws UnsatisfiedLinkError {
11     [...]
12     System.loadLibrary(lib.getName()); // might throw UnsatisfiedLinkError
13   }
14
15   [...]
16
17   public static String readline(String prompt, boolean addToHist)
18                throws EOFException, IOException, UnsupportedEncodingException {
19     [...]
20     String line = readlineImpl(prompt);
21     if ((line != null) && (addToHist)) {
22       addToHistory(line);
23     }
24     return line;
25   }
26
27   public static void addToHistory(String line) {
28     [...]
29     addToHistoryImpl(line);
30   }
31
32   [...]
33
34   private native static String readlineImpl(String prompt)
35                        throws EOFException, UnsupportedEncodingException;
36
37   private native static void addToHistoryImpl(String line);
38   [...]
39 }

Listing 2

Ausschnitt der erzeugten C-Headerdatei

01 /* DO NOT EDIT THIS FILE - it is machine generated */
02 #include <jni.h>
03 /* Header for class org_gnu_readline_Readline */
04 [...]
05 /*
06  * Class:     org_gnu_readline_Readline
07  * Method:    initReadlineImpl
08  * Signature: (Ljava/lang/String;)V
09  */
10 JNIEXPORT void JNICALL Java_org_gnu_readline_Readline_initReadlineImpl
11   (JNIEnv *, jclass, jstring);
12
13 /*
14  * Class:     org_gnu_readline_Readline
15  * Method:    cleanupReadlineImpl
16  * Signature: ()V
17  */
18 [...]

Magie der Bilder

In Java implementierte Webanwendungen mit intensiver Bildverarbeitung stützen sich häufig auf Jmagick [3]. Das ist ein Java-C-Interface zu Imagemagick und zugleich ein gutes Beispiel, warum JNI-Programmierung Verdruss bereiten kann. Ein Problem betrifft die Stabilität im Ganzen: Eingebundener fehlerhafter C-Code holt Java-untypische Probleme in die Anwendung, oft Abstürze oder Speicherlecks, die den Applikationsserver nach und nach herunterziehen.

Ein zweites Problem ist bei Imagemagick hausgemacht. Dessen Entwickler verändert öfter die Schnittstellen. Deshalb funktioniert der Jmagick-Wrapper nur genau mit der Imagemagick-Version, für die er gebaut ist. Administratoren müssen entweder eine distributionsfremde Version von Imagemagick installieren oder die Jmagick-Version genau für das aktuelle Imagemagick-ABI bauen – was aber Code-Änderungen an Jmagick nach sich zieht. Die Pflege der Codebasis ist dementsprechend schwierig.

Die Alternative Im4java [4], ebenfalls ein Projekt des Autors, verzichtet deshalb auf die Performancevorteile des JNI, bietet dafür aber eine stabile, objektorientierte Schnittstelle auf Imagemagick. Die Einbindung erfolgt hier über den direkten Aufruf des ausführbaren Imagemagick-Programms, typischerweise »convert« , mittels der »ProcessBuilder« -Klasse. Damit läuft der Java-fremde Code in einem anderen Prozess und richtet niemals Schaden an.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 3 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Jython: Java-basierter Python-Interpreter in Version 2.2

    Das Jython-Projekt hat Version 2.2 seines in Java geschriebenen Interpreters für die Skriptsprache Python veröffentlicht.

  • 80 Prozent Java

    Reine Java-Programme laufen auf allen Plattformen. Doch manchmal ist eine engere Verzahnung mit dem jeweiligen Betriebssystem notwendig. Wie das zu bewerkstelligen ist und welche Pakete es dafür in der Open-Source-Landschaft bereits gibt, zeigt dieser Beitrag.

  • Fremde Federn

    Java und Tcl ergänzen sich bestens und profitieren voneinander: Ein Testskript für eine Java-Applikation ist in Tcl schneller geschrieben als in Java. Andererseits wollen Tcl-Entwickler gelegentlich Java-Pakete nutzen. Jacl und Tclblend geben ihnen diese Freiheiten.

  • Bilder-Zauberer

    Das Java-SDK bietet in der aktuellen Version einige Möglichkeiten für die Bildbearbeitung. Einfacher und performanter geht es aber mit JMagick, dem Java-API für das bekannte Image-Magick-Toolkit.

  • Javascript: Mozilla Firefox-Vorversion hält bei Google Chrome mit

    Der Google-Konzern hebt als Vorteil seines Chrome-Browsers unter anderem die Javascript-Engine V8 hervor, die neue Maßstäbe in Sachen Geschwindigkeit setzen soll. Linux-Magazin Online fand in einem kurzen Test jedoch heraus, dass die künftige Firefox-Generation durchaus mithalten kann.

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.