Alle Neuerungen von Java 8 über die Javadoc finden

Im folgenden Beispiel wollen wir ein kleines Doclet schreiben, das Klassen, Methoden und Konstruktoren ausgibt, die das Tag @since 1.8 (bzw. @since 8, was aber eigentlich falsch ist) tragen. So lässt sich leicht ermitteln, was in der Version Java 8 alles hinzugekommen ist. Doclets werden normalerweise von der Kommandozeile aufgerufen und dem javadoc-Tool übergeben. Unser Programm vereinfacht das, indem es direkt das Tool über Java mit dem passenden Parameter aufruft. tools.jar muss dafür im Klassenpfad sein und die Dokumentation ausgepackt am angegeben Ort.

package com.tutego.tools.javadoc;

import java.util.*;
import java.util.function.Predicate;
import com.sun.javadoc.*;
import com.sun.tools.javadoc.Main;

public class SinceJava8FinderDoclet {

  public static boolean start( RootDoc root ) {
    for ( ClassDoc clazz : root.classes() )
      processClass( clazz );
    return true;
  }

  private static void processClass( ClassDoc clazz ) {
    Predicate<Tag> isJava18 = tag -> tag.text().equals( "8" ) || tag.text().equals( "1.8" );

    if ( Arrays.stream( clazz.tags( "since" ) ).anyMatch( isJava18 ) )
      System.out.printf( "Neuer Typ %s%n", clazz );

    for ( MethodDoc method : clazz.methods() )
      if ( Arrays.stream( method.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neue Methode %s%n", method );

    for ( ConstructorDoc constructor : clazz.constructors() )
      if ( Arrays.stream( constructor.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neuer Konstruktor %s%n", constructor );

    for ( FieldDoc field : clazz.fields() )
      if ( Arrays.stream( field.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neues Attribut %s%n", field );
  }

  public static void main( String[] args ) {
    String[] params = {
        "-quiet", "-XDignore.symbol.file",
        "-doclet", SinceJava8FinderDoclet.class.getName(),
        "-sourcepath", "C:/Program Files/Java/jdk1.8.0/src/",
//        "java.lang",  // Nur java.lang
        "-subpackages", "java:javax"  // Alles rekursiv unter java.* und javax.*
    };
    Main.execute( params );
  }
}

Unsere main(String[])-Methode ruft das JDK-Doclet-Programm über Main.execute(String[]) auf und übergibt die eigene Doclet-Klasse per Parameter – die Argumente von execute(String[]) erinnern an die Kommandozeilenparameter. Das Doclet-Hauptprogramm wiederum ruft unsere start(RootDoc root)-Methode auf – das Gleiche würde auch passieren, wenn das Doclet von außen über javadoc aufgerufen würde. Unser start(RootDoc) läuft über alle ermittelten Typen und übergibt zum Abarbeiten der Innereien die Verantwortung an processClass(ClassDoc). Die Metadaten kommen dabei über diverse XXXDoc-Typen. Ein Precidate zieht den Tag-Test heraus, ein weiterer Einsatz der neuen Java 8 Streams würde das Programm nicht übersichtlicher machen.

Das Programm nutzt ein paar Tricks, um die Ausgabe auf das Wesentliche zu konzentrieren. Der Schalter –quit schaltet den üblichen Ladestatus, der zu Ausgaben wie

Loading source files for package java.lang…

Loading source files for package java.applet…

Loading source files for package java.awt…

führt ab.

Der Schalter -XDignore.symbol.file wiederum unterdrückt Meldungen wie diese hier:

C:\…\src\java\lang\Class.java:57: warning: Unsafe is internal proprietary API and may be removed in a future release

import sun.misc.Unsafe;

^

Die Meldungen landen auf dem System.err-Kanal, sodass sie sich auch mit System.setErr(…) in einem ausgabeverwerfenden Strom geschickt werden können um sie zu unterdrücken.

JavaFX vertical text scroller in effectively 4 lines

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class FxScroller extends Application
{
  @Override
  public void start( Stage stage )
  {
    Text text = new Text( 600, 20, "It is a period of civil war. Rebel spaceships, striking from a hidden base, have won their first victory against the evil Galactic Empire." );
    new Timeline( new KeyFrame( Duration.seconds( 20 ),
                  new KeyValue( text.xProperty(), -text.getBoundsInLocal().getWidth() - 1) ) ) .play();
    stage.setScene( new Scene( new Group( text ), 600, 30 ) );
    stage.show();
  }

  public static void main( String[] args )
  {
    launch( args );
  }
}

Thema der Woche: JSON-Verarbeitung

JSON ist ein beliebtes Format für Web-Services geworden, ließ die Einführung unter http://www.json.org/. Was ergeben die Diskussionen unter http://stackoverflow.com/questions/3536893/what-are-the-pros-and-cons-of-xml-and-json für Vor-/Nachteile?

Für Java gibt es diverse Bibliotheken und seit Java EE 7 ist ein Reader/Writer auch Teil vom Standard. In der Regel werden Autoren aber zu externen Libs greifen, etwa http://www.json.org/java/index.html, https://github.com/FasterXML/jackson oder http://jettison.codehaus.org/.

Beziehe das Jar für json.org, verstehe das Beispiel http://www.concretepage.com/java/example_json_java und lasse es laufen.

Mache dich kurz mit http://www.geojson.org/ vertraut. Was sagt die http://www.geojson.org/geojson-spec.html zum Unterschied von Polygon und MultiPolygon?

http://www.mapfish.org/svn/mapfish/contribs/java-geojson/ ist eine Bibliothek für das GeoJSON-Format; intern baut es auf json.org auf. Binde die Bibliothek ein und beziehe über vom Webserver http://openstreetmap.us/~migurski/vector-datasource/ eine JSON-Datei und gib die erkannten Geo-Objekte auf der Konsole aus. Für http://tile.openstreetmap.us/vectiles-water-areas/12/656/1582.json soll zum Beispiel so etwas erscheinen:

MultiPolygon mit Koordinaten [-122.30168,37.85751],[-122.30029,37.85071],[-122.30105,37.84776],[-122.30078,37.84630],[-122.30241,37.84564],[-122.29997,37.84620], …
Polygon mit Koordinaten [-122.34366,37.85751],[-122.34366,37.78808],[-122.34375,37.78808], …

Kommerzielle Unterstützung für GlassFish läuft aus

Quelle:

Bemerkungen dazu unter

Oracle handelt in meinen Augen (wieder einmal) aus rein ökonomischen Interessen; es geht nicht gut, zwei Produkte in einem Marktsegment zu positionieren, die Geschichte hatten wir schon mit Oracle Database und MySQL.

Möglicherweise wird GlassFish (und die assoziierten Java EE-Teile, wie Web-Services, OR-Mapper) eine Spielwiese für Technologien, die dann in WebLogic übertragen werden, wenn sie funktionieren, und dort dann exklusiv verbessert und optimiert.

Ob ich Kunden nun zu GlassFish raten würde? Eher nicht. Bis gestern war ich absoluter GF-Fan und habe den Server immer empfohlen, auch gegen den starken JBoss, doch wenn kein kommerzieller Support vorhanden ist, werden große Unternehmen ihn schlicht nicht einsetzen wollen.

Bye Bye GF

Besonderheit bei vererbten Konstruktoren mit Ausnahmen

Implementiert eine Unterklasse einen eigenen Konstruktor, und ruft dieser super(…) für einen Konstruktor auf, der eine Ausnahme auslöst, so muss auch der Konstruktor der Unterklasse diese Ausnahme melden, denn der neue Konstruktor kann die Ausnahme nicht auffangen. In unsere Beispiel wäre also

public SubRandomAccessFile( File file, String mode ) {

try {

  super( file, mode );

} catch ( Exception e ) { }

}

illegal. Der Grund ist ganz einfach: Wenn der Konstruktor der Oberklasse eine Ausnahme auslöst, ist das Objekt nicht vollständig initialisiert. Und wenn der Konstruktor der Unterklasse dann die Ausnahme abfängt, würde ja die Unterklasse vielleicht nicht vollständig initialisierte Eigenschaften der Oberklasse erben, also ein halbgares Objekt. Das ist unerwünscht.

Was sagt eigentlich die Nielsen Norman Group zum iOS 7 Design?

Gemisches, wie man bei http://www.nngroup.com/articles/ios-7/ nachlesen kann. Eher ein negativer Grundton.

Is iOS 7 Fatally Flawed? The short answer is no. Simply because there is no such thing as fatally flawed designs: we can always learn from mistakes. What’s surprising is that we don’t Is iOS 7 Fatally Flawed?learn from someone else’s mistakes: Apple ignored some of the hurdles that Microsoft experienced with flat design and swipe ambiguity in Windows 8. We still have to see whether Apple’s strong design guidelines will protect most app designers from not getting lost in the flat 2D world. Early experience with applications redesigned for iOS 7 is fairly negative: several have worse usability than their iOS 6 versions.

NetBeans IDE 7.4 mit JDK 8 und mehr

Das konnte ich gerade bei http://www.theserverside.com/discussions/thread.tss?thread_id=77744 lesen:

  • HTML5 features available in Java EE and PHP projects
  • Cordova application development
  • Support for Android and iOS devices and emulators
  • Preview support for JDK 8 features
  • Initial editing support for Knockout, AngularJS, and ExtJS frameworks

Mehr unter https://netbeans.org/community/releases/74/ und Download bei https://netbeans.org/downloads/.

JavaFX + CDI (Weld)

Put in the class path:

The challenge is to bring FXMLLoader and CDI together, because JavaFX is creating naked objects by itself, now they have to be „CDI-aware“.

package tutego.fx;

import java.nio.charset.*;
import javafx.fxml.FXMLLoader;
import javafx.util.Callback;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;

public class FXMLLoaderProducer
{
  @Inject
  Instance<Object> instance;

  @Produces
  public FXMLLoader createLoader()
  {
    return new FXMLLoader( null, null, null, new Callback<Class<?>, Object>() {
      @Override public Object call( Class<?> param ) {
        return instance.select( param ).get();
      }
    }, StandardCharsets.UTF_8 );
  }
}

That was the hardest part.

The first regular class has the unique main(String[]) method and it’s a JavaFX application. It starts Weld, the CDI container.

package tutego.fx;

import java.io.IOException;
import javafx.application.Application;
import javafx.stage.Stage;
import org.jboss.weld.environment.se.*;

public class Main extends Application
{
  private Weld weld;

  public static void main( String[] args )
  {
    Application.launch( args );
  }

  @Override
  public void init()
  {
    weld = new Weld();
  }

  @Override
  public void start( Stage stage ) throws IOException
  {
    weld.initialize().instance().select( FxMain.class ).get().start( stage, getParameters() );
  }

  @Override
  public void stop()
  {
    weld.shutdown();
  }
}

Weld delegates to the FxMain class, the first CDI-enabled class:

package tutego.fx;

import java.io.*;
import javafx.application.Application.Parameters;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;
import javax.inject.Inject;

public class FxMain
{
  @Inject
  private FXMLLoader fxmlLoader;

  public void start( Stage stage, Parameters parameters ) throws IOException
  {
    try ( InputStream fxml = RandomController.class.getResourceAsStream( "/random.fxml" ) ) {
      Parent root = (Parent) fxmlLoader.load( fxml );
      stage.setScene( new Scene( root ) );
      stage.show();
    }
  }
}

The injected FXMLLoader now has to load the FXML-file random.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="tutego.fx.RandomController">
  <children>
    <Button onAction="#onButtonClick" text="Next random" />
    <Label id="text" fx:id="label" />
  </children>
</VBox>

In the FXML-file there is a reference to the FX Controller. JavaFX has to load it and can make the injections with the help of our very first class. A regular service is getting injected into the controller:

package tutego.fx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javax.inject.Inject;

public class RandomController
{
  @FXML
  private Label label;

  @Inject
  private RandomService randomService;

  @FXML
  public void onButtonClick()
  {
    label.setText( "Random " + randomService.nextInt() );
  }
}

The service itself is a simple singleton:

package tutego.fx;

import java.util.Random;
import javax.inject.Singleton;

@Singleton
public class RandomService
{
  private Random rnd = new Random();

  public int nextInt()
  {
    return rnd.nextInt();
  }
}

Thats it!

PS: When you start, dont forget to put a (even blank) beans.xml in META-INF.

Oracle Java SE 7u45 Update

Neu ist: A JDK for Linux ARM is also available in this release. Das kann man auf der Download-Seite auch ablesen:

Linux ARM v6/v7 Hard Float ABI
67.67 MB  
jdk-7u45-linux-arm-vfp-hflt.tar.gz

Linux ARM v6/v7 Soft Float ABI
67.68 MB  
jdk-7u45-linux-arm-vfp-sflt.tar.gz

Linux x86
115.62 MB  
jdk-7u45-linux-i586.rpm

Linux x86
132.9 MB  
jdk-7u45-linux-i586.tar.gz

Linux x64
116.91 MB  
jdk-7u45-linux-x64.rpm

Linux x64
131.7 MB  
jdk-7u45-linux-x64.tar.gz

Mac OS X x64
183.84 MB  
jdk-7u45-macosx-x64.dmg

Solaris x86 (SVR4 package)
139.93 MB  
jdk-7u45-solaris-i586.tar.Z

Solaris x86
95.02 MB  
jdk-7u45-solaris-i586.tar.gz

Solaris x64 (SVR4 package)
24.6 MB  
jdk-7u45-solaris-x64.tar.Z

Solaris x64
16.23 MB  
jdk-7u45-solaris-x64.tar.gz

Solaris SPARC (SVR4 package)
139.38 MB  
jdk-7u45-solaris-sparc.tar.Z

Solaris SPARC
98.17 MB  
jdk-7u45-solaris-sparc.tar.gz

Solaris SPARC 64-bit (SVR4 package)
23.91 MB  
jdk-7u45-solaris-sparcv9.tar.Z

Solaris SPARC 64-bit
18.26 MB  
jdk-7u45-solaris-sparcv9.tar.gz

Windows x86
123.49 MB  
jdk-7u45-windows-i586.exe

Windows x64
125.31 MB  
jdk-7u45-windows-x64.exe

Singleton in Java

Ein Singleton ist eine Klasse, von der es in einer Anwendung nur ein Exemplar gibt. Nützlich ist das für Dinge, die es nur genau einmal in einer Applikation geben soll, und davon gib es einige Beispiele:

· Eine grafische Anwendung hat nur ein Fenster.

· Eine Konsolenanwendung hat nur je einen Eingabe-/Ausgabestrom.

· Alle Druckaufträge wandern in eine Drucker-Warteschlage.

Unbestreitbar ist, dass es einmalige Objekte gibt, variantenreich ist jedoch der Weg dahin. Im Prinzip lässt sich unterscheiden zwischen einem Ansatz, bei dem

a) ein Framework sich um den einmaligen Aufbau des Objekts kümmert und dann auf Anfrage das Objekt liefert oder

b) wir selbst in Java-Code ein Singleton realisieren.

Die bessere Lösung ist ein Framework zu nutzen, namentlich CDI, Guice, Spring, Java EE, doch Java SE enthält keines davon, weswegen wir zur Demonstration den expliziten Weg gehen.

Die technischen Realisierungen sind vielseitig; in Java bieten sich zur Realisierung von Singletons Aufzählungen (enum) und normale Klassen an. In Folgendem wollen wir ein Szenario annehmen, bei dem eine Anwendung zentral auf Konfigurationsdaten zurückgreifen möchte.

Singletons über Aufzählungen

Eine guter Weg für Singletons bieten Aufzählungen – auf den ersten Blick scheint ein enum nicht dafür gemacht, denn eine Aufzählung impliziert ja irgendwie mehr als ein Element – doch die Eigenschaften vom enum sind perfekt für ein Singleton. Die Idee dabei ist, genau ein Element anzubieten, gerne INSTANCE genannt, was letztendlich ein Exemplar der Aufzählungskasse wird, und die normalen Methoden:

public enum Configuration {

INSTANCE;

private Properties props = new Properties( System.getProperties() );

public String getVersion() {

return "1.2";

}

public String getUserDir() {

return props.getProperty( "user.dir" );

}

}

Der Typ Configuration deklariert neben der später öffentlichen statischen Variable INSTANCE auch noch eine interne Variable props, die von der Aufzählung genutzt werden kann, um dort Zustände abzulegen oder zu erfragen. Wir machen das im Beispiel nur lesend über getUserDir().

Ein Nutzer greift wie üblich auf die enum-Eigenschaften zu:

System.out.println( Configuration.INSTANCE.getVersion() ); // 1.2

System.out.println( Configuration.INSTANCE.getUserDir() ); // C:\Users\…

Singletons über Klassen

Ein alternativer Weg – und der übliche vor Java 5 – arbeit mit einer Klasse und privatem Konstruktor, zusammen mit einer statischen Anfrage-Methode, die das Objekt liefert:

public class Configuration2 {

private static final Configuration2 INSTANCE = new Configuration2();

public final static Configuration2 getInstance() {

return INSTANCE;

}

private Configuration2() {

}

private Properties props = new Properties( System.getProperties() );

public String getVersion() {

return "1.2";

}

public String getUserDir() {

return props.getProperty( "user.dir" );

}

}

Interessant sind einmal der private Konstruktor und zum anderen die statische Anfrage-Methode getInstance(). Wenn ein Konstruktor privat ist, bedeutet das noch lange nicht, dass keine Exemplare mehr erzeugt werden können. Ein privater Konstruktor besagt nur, dass er von außen nicht sichtbar ist – aber die Klasse selbst kann ihn ebenso wie private Methoden »sehen« und zur Objekterzeugung nutzen. Objektmethoden kommen dafür nicht in Frage, da ähnlich wie beim Henne-Ei-Problem ja vorher ein Objekt nötig wäre. Es bleiben somit die statischen Methoden als Erzeuger. Und das ist das, was wir wollen: Keine Exemplare von außen, nur von innen. Und da die statische Variable INSTANCE ja genau ein Objekt referenziert, kann die statische Methode diese Referenz nach außen geben.

Die Nutzung der zweiten Variante ist nicht sonderlich unterschiedlich, hat aber wohl eine andere Syntax, sodass ein Refactoring von einer Lösung in die andere Codeänderungen nach sich zieht:

System.out.println( Configuration2.getInstance().getVersion() ); // 1.2

System.out.println( Configuration2.getInstance().getUserDir() ); // C:\Users\…

Oftmals findet sich in Implementierungen eines Singletons noch eine Optimierung, in dem erst in getInstance() das Exemplar aufgebaut wird. Dazu muss aber noch die Methode mit synchronized ausgezeichnet werden, was vor nebenläufigen Zugriffen schützt, sodass nur ein Thread die Methode betreten kann und ein potenziell anderer Thread so lange warten muss, bis der erste Thread die Methode wieder verlassen hat.

GUI-Builder für JavaFX und Swing

Mit einem GUI-Builder lassen sich grafische Oberflächen über ein grafisches Werkzeug einfach aufbauen. In der Regel bietet ein GUI-Bilder eine Zeichenfläche und eine Symbolleiste mit Komponenten, die per Drag and Drop angeordnet werden. Zentral bei dem Ansatz ist das WYSIWYG-Prinzip (What You See Is What You Get), dass nämlich im Designschritt schon abzulesen ist, wie die fertige Oberfläche aussieht.

Ein GUI-Builder erzeugt eine Repräsentation der grafischen Oberfläche, die im Prinzip auch von Hand zu erstellen wäre – allerdings ist der Aufwand sehr groß und für jeden nachvollziehbar, der schon einmal in HMTL eine neue Tabellenspalte hinzugeführt hat. Es gibt immer wieder Diskussion über das Für und Wider doch ist es wie mit allen Tools: richtig eingesetzt kann ein GUI-Builder viel Arbeit sparen.

GUI-Builder für JavaFX

Der JavaFX Scene Builder ist ein Werkzeug von Oracle und nennt sich selbst „A Visual Layout Tool for JavaFX Applications“. Er ist kein Teil vom JDK, sondern muss unter http://www.oracle.com/technetwork/java/javafx/tools/index.html bezogen und installiert werden. Danach stehen komfortable Werkzeuge zum Entwurf von Oberflächen und deren Verschönerung mit CSS nichts im Wege.

NetBeans bietet von Haus aus Unterstützung im Entwurf grafischer Oberflächen, denn ein GUI-Bilder ist integriert, und eine Zusatzinstallation ist nicht nötig. Das gibt uns direkte Möglichkeiten, Swing und auch JavaFX spielerisch zu erfahren.[1]

Für Eclipse gibt es keinen speziellen GUI-Builder, das ist auch eigentlich gar nicht nötig, denn der Scene Builder kann in Eclipse integriert werden.[2] Zwar kein direkter WYSIWYG-Editor, aber immerhin ein Werkzeug im Umgang mit XML ist das quelloffenes Eclipse-Plugin e(fx)clipse unter http://efxclipse.org/.

GUI-Builder für Swing

Während NetBeans für Swing gute Unterstützung mitbringt, ist bei Eclipse standardmäßig kein GUI-Builder integriert. Es gilt also, ein Plugin nachzuinstallieren. In den letzten Jahren kamen und gingen verschiedene GUI-Builder, aber letztendlich hat sich der WindowsBuilder (https://developers.google.com/java-dev-tools/wbpro/) von Google als De-facto-Standard etabliert. Über den Update-Mechanismus von Eclipse wird er installiert. Eine Installationsanleitung findet sich auf der Webseite. Neben Swing nimmt der WindowsBuilder gleich noch GWT, SWT und XWT (Eclipse XML Window Toolkit) mit.


[1] Didaktiker nennen das »exploratives Lernen«.

[2] http://docs.oracle.com/javafx/scenebuilder/1/use_java_ides/sb-with-eclipse.htm