Sonntag, 31. Mai 2009

NetBeans 6.7 im nächsten Monat

Die JavaOne startet in nicht einmal zwei Tagen – ein prima Termin, um NetBeans 6.7 zu veröffentlichen, das sich derzeit noch im Beta-Stadium befindet.

Die neue Version von Suns Entwicklungsumgebung bietet viele Neuerungen und Verbesserungen, u.a. einen erweiterten Profiler, die Unterstützung von GlassFish v3 sowie die Integration von Suns Entwickler-Portal Kenai.

Für Entwickler, die NetBeans unter Mac OS X nutzen, wird dies ein besonders schönes Release. Das Projektfenster wurde an das native Aussehen des Systems angepasst und erinnert nun deutlich an Xcode:

Mittwoch, 29. April 2009

@SuppressWarnings("unchecked")

Seit Version 5.0 kennt Java das Konzept der Generics, mit denen u.a. Kollektionen mit Typen parametrisiert und typsicherer gemacht werden können.

Leider lassen sich damit nicht alle Stellen perfekt absichern – insbesondere bei Hibernate bzw. JPA wird man beim Ausführen von Abfragen (Queries) immer wieder auf "Type safety"-Compiler-Warnungen stoßen:

An sich ist das kein Problem, denn mit der bestehenden API gibt es für den Compiler keine sinnvolle Möglichkeit, vom Query-String auf den Ergebnis-Typ zu schließen. Und Entwicklungsumgebungen wie Eclipse bieten die einfache Lösung an, diese unumgängliche Warnung mit der @SuppressWarnings-Annotation zu unterdrücken.

Nur leider schreibt Eclipse die Annotation immer vor die umgebende Methode, was alle weiteren – vielleicht wichtigen – Typ-Warnungen in der Methode ebenfalls unterdrückt:
@SuppressWarnings("unchecked")
public List<Benutzer> findAllBenutzer() {
Query q = session.createQuery("from Benutzer");
return q.list();
}
Das muss nicht sein! Sehen wir uns dazu den Quelltext der @SuppressWarnings-Annotation an:
@Target({TYPE, FIELD, METHOD, PARAMETER,
CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
LOCAL_VARIABLE bedeutet, dass wir die Annotation auch an eine lokale Variablendeklaration schreiben dürfen. Wenn wir also in der Methode eine temporäre Variable einführen, können wir das Unterdrücken der Warnung auf die eine relevante Zeile beschränken:
public List<Benutzer> findAllBenutzer() {
Query q = session.createQuery("from Benutzer");

@SuppressWarnings("unchecked")
List<Benutzer> alle = q.list();

return alle;
}
Für die JPA-Query-Methoden getResultList() und getSingleResult() gilt dies entsprechend.

Dienstag, 21. April 2009

Oracle kauft Sun

Nun ist es also geschehen: Sun wird verkauft, und nicht etwa an IBM (die Übernahmeverhandlungen waren erst kürzlich gescheitert), sondern an Oracle.

Was dies für die Java-Technologie und die diversen Sun-Java-Produkte konkret bedeutet, bleibt abzuwarten. Immerhin ist Java seit langem gut in bestehende Oracle-Produkte integriert und dürfte für Oracle auch weiterhin von strategischer Bedeutung sein.

Spannend wird es für Suns Application Server GlassFish, der sich seit über einem Jahr deutlich steigender Beliebtheit erfreut. Hier ist zu hoffen, dass Oracle das Potential dieses nun dritten Application Servers im Produktportfolio kennt und nutzt. Berechtigt ist diese Hoffnung allemal, schließlich hat Oracle TopLink Essentials als JPA-Referenzimplementation zu GlassFish beigesteuert.

Mittwoch, 8. April 2009

Serialisierbarer ByteArrayOutputStream

Ein typisches Problem in einer mehrschichtigen Web-Anwendung besteht darin, eine Datei (beispielsweise ein auf dem Server generiertes PDF-Dokument) zum Client/Web-Frontend zu übertragen (oder nach einem Datei-Upload entsprechend umgekehrt). Die einfache Lösung mit Streams schlägt fehl, sobald Sender und Empfänger nicht mehr lokal in derselben Java Virtual Machine laufen, sondern entfernt in verschiedenen JVMs. Die Streams müssten nun entweder entfernt aufrufbar (Remote) oder aber serialisierbar (Serializable) sein – beides sind sie nicht. Die Serialisierbarkeit ist standardmäßig nicht vorgesehen, da Streams geräteabhängig sind.

Eine einfache Lösung für das Versenden kleinerer Binärdateien (wenige hundert KB) macht den Standard-ByteArrayOutputStream serialisierbar, was kein Problem ist, da der ByteArrayOutputStream eine reine Java-Speicher-Implementierung und somit geräteunabhängig ist. Der Sender kann den Stream wie gewohnt mit write() füllen, und der Empfänger kann den Stream mit den üblichen Methoden auswerten. In einem Servlet kann man den Stream z.B. mit baos.writeTo(response.getOutputStream()) direkt zum Client schicken.

Für die Implementierung des serialisierbaren ByteArrayOutputStreams reicht es nicht aus, die neue Unterklasse das Serializable-Interface implementieren zu lassen. Man muss zusätzlich noch die Methoden writeObject() und readObject() implementieren, die den internen Stream-Puffer explizit serialisieren:

public class SerializableByteArrayOutputStream
extends ByteArrayOutputStream
implements Serializable {

private void writeObject(ObjectOutputStream stream)
throws IOException {
stream.writeInt( count );
stream.writeObject( buf );
}

private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
count = stream.readInt();
buf = (byte[]) stream.readObject();
}
}

Der vollständige Quelltext der Klasse
SerializableByteArrayOutputStream kann hier abgerufen werden.

Wer eine umfassendere Lösung sucht oder große Dateien übertragen muss, sollte sich die RMIIO-Bibliothek anschauen.

Mittwoch, 1. April 2009

Proxy-Konfiguration für VisualVM

Wenn man mit VisualVM in einem Netzwerk arbeitet, das über einen Proxy ans Internet angebunden ist, hat VisualVM Probleme mit dem Nachladen seiner Plugins – was schade ist, denn dadurch verschenkt man die Hälfte der Möglichkeiten.

Der Proxy kann leider nicht in VisualVM selbst konfiguriert werden, sondern muss mit Aufrufparametern übergeben werden:

visualvm -J-DproxyHost=mein.proxy.com -J-DproxyPort=1234

Aber Achtung: Dies sind nicht die üblichen Java-Proxy-Parameter http.proxyHost und http.proxyPort! Das "http." fehlt jeweils.

Außerdem scheint die Konfiguration mit dem im JDK 6 mitgelieferten VisualVM nicht zu funktionieren. Mit dem separat herunterladbaren VisualVM 1.1.1 klappt es aber wie gewünscht.

Samstag, 28. März 2009

Scala ist auch eine Oper

... aber natürlich vor allem eine funktionale, objektorientierte Programmiersprache für die Java Virtual Machine :-)

Scala hat das Zeug dazu, die nächste große Sprache nach bzw. neben Java zu werden. Viele Ausdrücke lassen sich in Scala einfacher und kürzer als in Java schreiben, dennoch bleibt die statische und starke Typisierung wie bei Java erhalten. Ein großes Plus ist zudem die nahtlose Integration mit den unzähligen bestehenden Java-Bibliotheken. Und Scala ist nicht wirklich neu und nur irgendwie gerade cool, sondern bereits acht Jahre alt und stabil.

Zum Einstieg verwendet man am besten Eclipse 3.4 (das "Classic"- oder "Java EE"-Paket). Ein JDK 5.0 oder neuer sollte bereits installiert sein. Nun fehlt nur noch das Scala-Plugin, das man in Eclipse im Menü Help > Software Updates... mit der Update-URL

http://www.scala-lang.org/scala-eclipse-plugin

herunterladen lässt.

Wechselt man in die Scala-Perspektive, kann man unter File > New ein neues "Scala Project" anlegen. Wie aus Java gewohnt legt man ein Paket an und in diesem Paket dann ein "Scala Object" (!). Richtig gelesen, Scala unterstützt nicht nur Klassen, sondern auch einzelne Objekte. Wenn wir dieses Objekt von Application erben lassen, entspricht das der main-Methode in Java:


Scala bietet Typinferenz, d.h. man muss beim Deklarieren einer Variablen nicht zwingend den Typ angeben, wenn Scala diesen aus dem Kontext eindeutig ableiten kann. Die Variable ist dann trotzdem zur Übersetzungszeit typsicher, man kann also keine inkompatiblen Werte zuweisen:


Wie bei funktionalen Sprachen üblich, liegt eine der Stärken in der Listenverarbeitung. Listen können mit einer Java-ähnlichen Syntax angelegt werden (es geht auch funktionaler, siehe erster Screenshot):

val früchte = List("Äpfel", "Birnen", "Orangen")

Entweder kann man die Liste dann mit einer Java 5-ähnlichen for-each-Schleife ausgeben:

for (frucht <- früchte) { println(frucht) }

Oder man nutzt ein anonymes Funktionsliteral, eine sogenannte Funktion höherer Ordnung, die man als Wert an die foreach-Methode der Liste übergibt:

früchte.foreach(f => println(f))

Da man den Punktoperator beim Methodenaufruf weglassen darf und println nur ein Argument erwartet, geht das auch noch kürzer:

früchte foreach println

Und immer daran denken: Auch wenn das so langsam nach einer Skriptsprache aussieht (und tatsächlich ähnlich schnell programmiert werden kann), haben wir hierbei statische, starke, vom Compiler geprüfte Typisierung!

Soweit fürs Erste, das sollte als Appetitanreger reichen :-)

Mittwoch, 25. März 2009

Monitoring und Profiling mit VisualVM

Am Wochenende habe ich einen kleinen Vortrag über VisualVM gehalten. Dieses nützliche Werkzeug ist seit dem Update 7 fester Bestandteil des JDK 6. Es bietet gute Überwachungsmöglichkeiten für laufende Java-Anwendungen (sowohl lokal als auch auf entfernten Rechnern). Beim Profiling kann es zwar nicht ganz mit kommerziellen Lösungen mithalten, bietet aber dennoch für viele Situationen vollkommen ausreichende Auswertungen (z.B. die Aufrufstellen einer Methode).

VisualVM benötigt Java 6 als Laufzeitumgebung, kann aber Anwendungen schon ab Java 1.4 überwachen. Faustregel: Je neuer die Laufzeitumgebung des auszuwertenden Programms ist und je lokaler sie läuft, desto bessere Informationen liefert VisualVM.

Leider liefert Apple VisualVM auch mit dem neuesten Update ihrer Java SE 6-Implementation nicht mit. Sofern man dieses Update eingespielt hat, kann man VisualVM 1.1.1 aber problemlos separat herunterladen und (durch Auspacken des ZIP-Archivs) installieren.

Da es gute Gründe gibt, als Standard-Java-Version unter Mac OS X derzeit noch 5.0 einzusetzen, muss man Java 6 beim Aufruf im Terminal explizit als Parameter angeben:

HeartOfGold:visualvm-1.1.1 much$ bin/visualvm --jdkhome /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/ &


Das Profiling funktioniert mit der Apple-Java-Implementierung noch nicht wirklich zuverlässig... Eventuell ist ein älterer Bug immer noch nicht vollständig korrigiert. Immerhin stehen die Monitoring-Möglichkeiten komplett und stabil zur Verfügung.

Mit dem neuen "Memory Sampler"-Plugin können aber zumindest Live-Speichervergleiche (Deltas) ermittelt werden, was einen wichtigen Aspekt des Memory-Profilings abdeckt. Und der Memory Sampler läuft zum Glück auch unter Mac OS X.