Die Entwicklungsumgebung IntelliJ IDEA ist seit längerem der Geheimtipp für Java-Entwickler. Doch während Eclipse und NetBeans kostenlos erhältlich und weit verbreitet sind, schreckten viele vor dem dreistelligen Kaufpreis für eine IDE(A) zurück.
Mit der kommenden Version 9.0 wird IntelliJ IDEA nun Open Source und steht seit heute auch in einer kostenlosen Community Edition zur Verfügung. Mit dieser Edition kann Java SE, Groovy und Scala programmiert werden (inkl. Debugging, Refactoring, Testen, Versionsverwaltung etc.).
Für die Entwicklung von Web- und Enterprise-Applikationen wird die weiterhin kostenpflichtige Ultimate Edition benötigt, die neben aktuellen und künftigen Standards (Java EE 6 etc.) zahlreiche Programmiersprachen, Frameworks und Versionsverwaltungssysteme zusätzlich unterstützt.
Fazit: Für professionelle JEE-Entwicklung ist zwar nach wie vor die kostenpflichtige Ultimate Edition notwendig, aber zumindest kann sich nun jeder einen ausführlichen Eindruck von IntelliJ verschaffen. Und das hat diese Entwicklungsumgebung durchaus verdient.
Donnerstag, 15. Oktober 2009
Dienstag, 13. Oktober 2009
Snow Leopard und Rosetta
Schon seit den ersten Mac OS X-Versionen können Java-Applikationen in einer speziellen Verzeichnisstruktur als "normale" Mac OS X-Anwendung verpackt werden, so dass sie u.a. mit einem eigenen Programmsymbol dargestellt werden. Damit solche Application Bundles Java-Bytecode ausführen können, enthalten sie als nativen Mach-O-Startcode im Verzeichnis
Führt man ältere, noch unter PowerPC (PPC) Mac OS X zusammengebaute Java-Application-Bundles unter Mac OS X 10.6 "Snow Leopard" aus, erhält man eventuell den Hinweis, dass man den auf der Snow-Leopard-Installations-DVD enthaltenen PPC-Emulator "Rosetta" installieren muss, um die Anwendung starten zu können. Obwohl Apple seit Mac OS X 10.4 alte PPC-JavaApplicationStubs erkennt und als 32-Bit-Intel-Prozess neu startet, muss dafür Rosetta installiert sein – und genau das ist seit Snow Leopard nicht mehr standardmäßig der Fall.
Die einfachste Lösung, die zudem Rosetta nicht benötigt, ist, den alten Stub im Application Bundle durch eine Kopie der aktuelle Version
/Contents/MacOS/ die Datei JavaApplicationStub:
Führt man ältere, noch unter PowerPC (PPC) Mac OS X zusammengebaute Java-Application-Bundles unter Mac OS X 10.6 "Snow Leopard" aus, erhält man eventuell den Hinweis, dass man den auf der Snow-Leopard-Installations-DVD enthaltenen PPC-Emulator "Rosetta" installieren muss, um die Anwendung starten zu können. Obwohl Apple seit Mac OS X 10.4 alte PPC-JavaApplicationStubs erkennt und als 32-Bit-Intel-Prozess neu startet, muss dafür Rosetta installiert sein – und genau das ist seit Snow Leopard nicht mehr standardmäßig der Fall.Die einfachste Lösung, die zudem Rosetta nicht benötigt, ist, den alten Stub im Application Bundle durch eine Kopie der aktuelle Version
/System/Library/Frameworks/JavaVM.framework/Resources/MacOS/JavaApplicationStub zu ersetzen. Dieser neue Stub enthält Code für die drei derzeit unterstützten Prozessorarchitekturen:Straylight:~ much$ file JavaApplicationStubWenn eine Java-Anwendung eine bestimmte Architektur nicht benötigt (z.B. weil nachgeladene JNI-Bibliotheken dafür nicht compiliert wurden), kann und sollte der entsprechende Code mit
JavaApplicationStub: Mach-O universal binary with 3 architectures
JavaApplicationStub (for architecture x86_64): Mach-O 64-bit executable x86_64
JavaApplicationStub (for architecture i386): Mach-O executable i386
JavaApplicationStub (for architecture ppc7400): Mach-O executable ppc
/usr/bin/lipo entfernt werden.
Dienstag, 1. September 2009
Java in Mac OS X 10.6 "Snow Leopard"
Der Schneeleopard ist also aus dem Käfig... Und während das nun "alte" Mac OS X 10.5 noch drei Implementierungen für Java 1.4, 5.0 und 6 mitbrachte, enthält Mac OS X 10.6 ausschließlich Java SE 6 (1.6.0_15) in einer 32-Bit- und einer 64-Bit-Version. Detaillierte Informationen zu beseitigten und bekannten Fehlern enthalten die Release Notes.
Damit auch Java 5-Anwendungen weitestgehend problemlos laufen, sind im Ordner /System/Library/Frameworks/JavaVM.framework/Versions noch die Unterordner 1.5 und 1.5.0 enthalten, aber beide sind Aliase (Symlinks) auf die Java 6-Implementierung.
Und obwohl QuickTime for Java schon seit längerem nicht mehr offiziell unterstützt wird, sind die QTJava-Bibliotheken immer noch vorhanden und funktionieren auch mit Java 6.
Mal abwarten, was die praktischen Erfahrungen in den kommenden Tagen zeigen.
Damit auch Java 5-Anwendungen weitestgehend problemlos laufen, sind im Ordner /System/Library/Frameworks/JavaVM.framework/Versions noch die Unterordner 1.5 und 1.5.0 enthalten, aber beide sind Aliase (Symlinks) auf die Java 6-Implementierung.
Und obwohl QuickTime for Java schon seit längerem nicht mehr offiziell unterstützt wird, sind die QTJava-Bibliotheken immer noch vorhanden und funktionieren auch mit Java 6.
Mal abwarten, was die praktischen Erfahrungen in den kommenden Tagen zeigen.
Mittwoch, 26. August 2009
Closures in JavaFX Script
JavaFX Script (die Programmiersprache für Suns neue RIA-Technologie JavaFX) ist eine objektorientierte, deklarative und funktionale Programmiersprache.
Als funktionale Sprache unterstützt sie Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). Ersteres bedeutet, dass Funktionen selber Werte sind – sie können also als Parameter übergeben und zurückgegeben werden. Letzteres erlaubt den Funktionswerten, dass sie sich den Zustand ihrer Umgebung (die lokalen Variablen) bei ihrer Erzeugung merken können.
Für viele sind Closures seltsame Konstrukte und ihre Einsatzmöglichkeiten nicht offensichtlich. Daher im Folgenden ein kleines, relativ leicht verständliches Beispiel, in dem mehrere Zähler mit individuellen Startwerten erzeugt und benutzt werden:
Trotz (bzw. gerade wegen) dieser impliziten Typisierung ist JavaFX Script im Gegensatz zu Skriptsprachen wie JavaScript statisch und streng typisiert. Bereits der Compiler ermittelt also die Datentypen und Signaturen von Variablen und Funktionen, sofern sie nicht explizit angegeben sind. Im Beispiel hat die Variable
Wie funktioniert das Skript? Beim Aufruf der Funktion
Man kann sich Closures als Objekte vorstellen, die aus einer einzigen Methode/Funktion bestehen und wie Objekte zusätzlich einen Zustand haben. Schön sehen kann man dies an den generierten Java-Bytecode-Klassendateien:
Closures sind prima geeignet, um damit z.B. Event-Handler zu definieren, denen man zusätzliche Informationen mitgeben kann (bei Farb-Setz-Buttons in einem Grafikprogramm beispielsweise die zu setzende Farbe). Dadurch kann man häufig auf das Schreiben von Event-Handler-Klassen verzichten, auch wenn dies in JavaFX Script ebenfalls möglich ist.
Vielleicht hat man es gemerkt: Ich halte JavaFX Script trotz des Namens ganz und gar nicht für eine Skriptsprache. Meines Erachtens wurde die Sprache vor allem deshalb so genannt, um zu zeigen, dass man damit in Wettbewerb zu Skriptsprachen wie Ruby tritt, die als agil und produktiv empfunden werden. JavaFX Script zeigt dabei sehr schön, dass sich Produktivität und statische, strenge Typisierung überhaupt nicht ausschließen müssen.
Als funktionale Sprache unterstützt sie Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). Ersteres bedeutet, dass Funktionen selber Werte sind – sie können also als Parameter übergeben und zurückgegeben werden. Letzteres erlaubt den Funktionswerten, dass sie sich den Zustand ihrer Umgebung (die lokalen Variablen) bei ihrer Erzeugung merken können.
Für viele sind Closures seltsame Konstrukte und ihre Einsatzmöglichkeiten nicht offensichtlich. Daher im Folgenden ein kleines, relativ leicht verständliches Beispiel, in dem mehrere Zähler mit individuellen Startwerten erzeugt und benutzt werden:
// closure.fxWer das Beispiel ausprobieren möchte, installiert sich das JavaFX 1.2 SDK und nutzt die Kommandozeile (oder NetBeans oder Eclipse mit dem JavaFX-Plugin):
function zaehlerMitStartwert(startwert: Integer) {
var n = startwert;
return function(): Integer { return n++ }
}
var next1 = zaehlerMitStartwert(10);
var next2 = zaehlerMitStartwert(20);
println( next1() ); // 10
println( next2() ); // 20
println( next2() ); // 21
println( next1() ); // 11
Straylight:~ much$ javafxc closure.fxDie ausgegrauten Elemente sind nicht wirklich notwendig und sollen nur das Skript für Java-Programmierer leichter verständlich machen. "return" ist an beiden Stellen optional, da der letzte Ausdruck in einer Funktion gleichzeitig deren Ergebnis definiert. Der Rückgabetyp ":Integer" der inneren, anonymen Funktion ist optional, da aus dem Datentyp des Ergebnisses der Rückgabetyp durch Typinferenz ermittelt werden kann.
Straylight:~ much$ javafx closure
10
20
21
11
Trotz (bzw. gerade wegen) dieser impliziten Typisierung ist JavaFX Script im Gegensatz zu Skriptsprachen wie JavaScript statisch und streng typisiert. Bereits der Compiler ermittelt also die Datentypen und Signaturen von Variablen und Funktionen, sofern sie nicht explizit angegeben sind. Im Beispiel hat die Variable
n also den Datentyp Integer, die Variablen next1 und next2 haben den Typ function():Integer und zaehlerMitStartwert hat den Typ function(:Integer):function():Integer :-)Wie funktioniert das Skript? Beim Aufruf der Funktion
zaehlerMitStartwert wird eine Funktion zurückgegeben, die bei jedem Aufruf die Variable n um eins erhöht zurückgibt. Obwohl die Variable n zur äußeren Funktion gehört und damit beim Aufruf der zurückgegebenen Funktion mit next1() bzw. next2() eigentlich gar nicht mehr vorhanden ist, merkt sich die innere Funktion die lokale Variable separat für jede zurückgegebene innere Funktion – und genau das macht sie zur Closure.Man kann sich Closures als Objekte vorstellen, die aus einer einzigen Methode/Funktion bestehen und wie Objekte zusätzlich einen Zustand haben. Schön sehen kann man dies an den generierten Java-Bytecode-Klassendateien:
closure.class und closure$1.class. Die innere, anonyme Funktion wird für die JVM also einfach als innere, anonyme Java-Klasse closure$1.class abgebildet.Closures sind prima geeignet, um damit z.B. Event-Handler zu definieren, denen man zusätzliche Informationen mitgeben kann (bei Farb-Setz-Buttons in einem Grafikprogramm beispielsweise die zu setzende Farbe). Dadurch kann man häufig auf das Schreiben von Event-Handler-Klassen verzichten, auch wenn dies in JavaFX Script ebenfalls möglich ist.
Vielleicht hat man es gemerkt: Ich halte JavaFX Script trotz des Namens ganz und gar nicht für eine Skriptsprache. Meines Erachtens wurde die Sprache vor allem deshalb so genannt, um zu zeigen, dass man damit in Wettbewerb zu Skriptsprachen wie Ruby tritt, die als agil und produktiv empfunden werden. JavaFX Script zeigt dabei sehr schön, dass sich Produktivität und statische, strenge Typisierung überhaupt nicht ausschließen müssen.
Dienstag, 25. August 2009
Hibernate 3.5 und JPA 2.0
Vor wenigen Tagen wurde die erste Betaversion von Hibernate 3.5 veröffentlicht. Sofern der Download von SourceForge klappt, kann man damit viele der Neuerungen von JPA 2.0 ausprobieren.
Hibernate 3.5 bietet keine wesentlichen neuen Hibernate-Features, und auch für die Unterstützung der neuen JPA-Version wurden vor allem standardkonforme Schnittstellen für bereits vorhandene Hibernate-Eigenschaften bereitgestellt. Dies ist wohl auch der Grund, warum die Hibernate-Version nicht gleich auf 4.0 heraufgesetzt wurde.
Schön ist meines Erachtens, dass ab Version 3.5 die JARs für die Hibernate-Annotationen und den JPA-EntityManager Bestandteil vom Hibernate-Kern (Core) geworden sind. Und die Einbindung von Envers dürfte diese Versionierungs-Bibliothek zum heißen Kandidaten für den De-Facto-Standard bezüglich Versionierung/Historisierung/Auditierung mit JPA machen.
Hibernate 3.5 bietet keine wesentlichen neuen Hibernate-Features, und auch für die Unterstützung der neuen JPA-Version wurden vor allem standardkonforme Schnittstellen für bereits vorhandene Hibernate-Eigenschaften bereitgestellt. Dies ist wohl auch der Grund, warum die Hibernate-Version nicht gleich auf 4.0 heraufgesetzt wurde.
Schön ist meines Erachtens, dass ab Version 3.5 die JARs für die Hibernate-Annotationen und den JPA-EntityManager Bestandteil vom Hibernate-Kern (Core) geworden sind. Und die Einbindung von Envers dürfte diese Versionierungs-Bibliothek zum heißen Kandidaten für den De-Facto-Standard bezüglich Versionierung/Historisierung/Auditierung mit JPA machen.
Mittwoch, 22. Juli 2009
Lokaler Aufruf von @Remote in GlassFish
GlassFish muss als Java EE 5-konformer Application-Server beim Aufruf von EJB-@Remote-Interfaces die Übergabeparameter und Rückgabewerte kopieren (serialisieren). Der Aufruf erfolgt also mit Wert-Semantik ("pass-by-value"), selbst wenn der Aufrufer und die aufgerufene Session-Bean innerhalb derselben JVM laufen ("co-located") und der Aufruf damit prinzipiell lokal erfolgen könnte (durch Über-/Rückgabe von Referenzen, entsprechend "pass-by-reference" genannt).
Obwohl GlassFish den eigentlichen Remote-Aufruf bereits gut optimiert, wenn sich Aufrufer und aufgerufene Bean auf demselben Server befinden, kostet das Kopieren der Parameter Zeit und Speicher. Wenn die Parameter große Datenmengen beinhalten, kann es sich daher als Performanz-Optimierung lohnen, die Parameter des lokalen Remote-Aufrufs entgegen der Spezifikation als Referenz übergeben zu lassen. Man muss dann aber bedenken, dass Änderungen an den Parameterdaten – wie bei @Local-Aufrufen – an allen Stellen sichtbar sind, die eine Referenz darauf halten.
Aktivieren lässt sich der lokale Aufruf von @Remote-Methoden in GlassFish für eine komplette Enterprise-Applikation (EAR) im sun-application.xml-Deskriptor wie folgt:
Und nochmal Achtung: Offenbar klappt die Optimierung nur innerhalb einer Anwendung (EAR), nicht aber zwischen mehreren separaten Anwendungen bzw. EJB-Modulen auf demselben Server.
Warum will man überhaupt eine nicht standardkonforme Referenz-Übergabe aktivieren? Kann man nicht besser @Local-Interfaces verwenden, die die erwähnten Performanz-Vorteile sowieso mit sich bringen? Ja, man sollte @Local-Interfaces nach Möglichkeit bevorzugen.
Es gibt aber Fälle, bei denen man nicht schon bei der Programmierung entscheiden kann bzw. möchte, wie die Bean-Aufrufe durchgeführt werden, beispielsweise weil man sich die Option offen halten möchte, ob Frontend (WAR) und Backend (EJB-JAR) gemeinsam in einem EAR oder aber separat bereitgestellt ("deployed") werden. Im Quelltext wird man dann die @Remote-Variante programmieren, hat aber mit dem
Sinnvoll erscheint dies vor allem dann, wenn man viele EJBs entfernt aufruft und alle Aufrufe auf einen Schlag optimieren will. Wenn man dagegen nur wenige EJBs entfernt nutzt oder nur einzelne Aufrufe optimieren möchte, kann man die Aufrufart – wenn auch mit etwas mehr Aufwand – über die Standard-XML-Deskriptoren ändern. Eine mögliche Realisierung ist hier beschrieben.
Obwohl GlassFish den eigentlichen Remote-Aufruf bereits gut optimiert, wenn sich Aufrufer und aufgerufene Bean auf demselben Server befinden, kostet das Kopieren der Parameter Zeit und Speicher. Wenn die Parameter große Datenmengen beinhalten, kann es sich daher als Performanz-Optimierung lohnen, die Parameter des lokalen Remote-Aufrufs entgegen der Spezifikation als Referenz übergeben zu lassen. Man muss dann aber bedenken, dass Änderungen an den Parameterdaten – wie bei @Local-Aufrufen – an allen Stellen sichtbar sind, die eine Referenz darauf halten.
Aktivieren lässt sich der lokale Aufruf von @Remote-Methoden in GlassFish für eine komplette Enterprise-Applikation (EAR) im sun-application.xml-Deskriptor wie folgt:
<sun-application>Oder für einzelne EJBs in sun-ejb-jar.xml:
<pass-by-reference>true</pass-by-reference>
</sun-application>
<sun-ejb-jar>Achtung: Zumindest GlassFish 2.1 scheint einen Bug zu haben, dass die Einstellung in
<enterprise-beans>
<ejb>
<pass-by-reference>true</pass-by-reference>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
sun-application.xml ignoriert wird, wenn sich in einem EJB-Modul (EJB-JAR) kein sun-ejb-jar.xml befindet. Abhilfe: Einfach einen (abgesehen vom Wurzel-Element) leeren Deskriptor ergänzen.Und nochmal Achtung: Offenbar klappt die Optimierung nur innerhalb einer Anwendung (EAR), nicht aber zwischen mehreren separaten Anwendungen bzw. EJB-Modulen auf demselben Server.
Warum will man überhaupt eine nicht standardkonforme Referenz-Übergabe aktivieren? Kann man nicht besser @Local-Interfaces verwenden, die die erwähnten Performanz-Vorteile sowieso mit sich bringen? Ja, man sollte @Local-Interfaces nach Möglichkeit bevorzugen.
Es gibt aber Fälle, bei denen man nicht schon bei der Programmierung entscheiden kann bzw. möchte, wie die Bean-Aufrufe durchgeführt werden, beispielsweise weil man sich die Option offen halten möchte, ob Frontend (WAR) und Backend (EJB-JAR) gemeinsam in einem EAR oder aber separat bereitgestellt ("deployed") werden. Im Quelltext wird man dann die @Remote-Variante programmieren, hat aber mit dem
pass-by-reference-Schalter später per Konfiguration die Möglichkeit, die Aufrufart einfach und schnell umzustellen.Sinnvoll erscheint dies vor allem dann, wenn man viele EJBs entfernt aufruft und alle Aufrufe auf einen Schlag optimieren will. Wenn man dagegen nur wenige EJBs entfernt nutzt oder nur einzelne Aufrufe optimieren möchte, kann man die Aufrufart – wenn auch mit etwas mehr Aufwand – über die Standard-XML-Deskriptoren ändern. Eine mögliche Realisierung ist hier beschrieben.
Donnerstag, 16. Juli 2009
Sein oder !sein, das ist hier die Frage
Echte C-Freaks werden mich dafür verachten, aber ich finde ausgeschriebene boolesche Operatoren wie
Während beispielsweise die EL beide Schreibweisen erlaubt, kennt Java leider nur die Symbol-Operatoren. Was tun? Zumindest für den Präfix-Operator
Nur: Muss man sich diese Methoden selber schreiben, oder gibt es dafür bereits fertige Bibliotheken? Im Netz habe ich leider nichts passendes gefunden.
not, and und or einfach lesbarer als !, && und || (und ja, ich habe jahrelang C und C++ programmiert und weiß, wovon ich rede). Ein Beispiel: if (!liste.isEmpty()) { ... }
if (not(liste.isEmpty())) { ... }
M.E. ist das Ausrufungszeichen beim Durchsehen des Quelltextes viel zu leicht zu übersehen (und Code wird normalerweise viel häufiger gelesen als geschrieben).Während beispielsweise die EL beide Schreibweisen erlaubt, kennt Java leider nur die Symbol-Operatoren. Was tun? Zumindest für den Präfix-Operator
not kann man statische Methoden definieren, die sich dann mittels statischer Imports wie in obigem Beispiel nutzen lassen: public static boolean not(boolean bval) {
return !bval;
}
public static Boolean not(Boolean bval) {
if (bval == null) {
return null;
}
else {
return !bval;
}
}
(Den kompletten Quelltext gibt es hier.)Nur: Muss man sich diese Methoden selber schreiben, oder gibt es dafür bereits fertige Bibliotheken? Im Netz habe ich leider nichts passendes gefunden.
Abonnieren
Posts (Atom)
