PDFs in/mit/aus Java erstellen, ein leidiges Thema

  • Selbst die PDF erstellen, mit allen Linien, Grafiken, Texten. Das geht etwa mit iText. Nachteil: Sehr aufwändig, insbesondere wenn der Kunde einmal sagt: Die Box bitte noch ein wenig nach links oben.
  • Mit Report-Programmen wie BIRT oder Japser arbeiten, die dann über iText die PDF rausspucken. Vorteil: Netter Report-Designer. Nachteil: Die Designer sind im Sekretariat, die nur Word oder vielleicht OO (OpenOffice, Libre Office) kennen, ungewohnt.
  • PDF mit XForms erstellen. Siehe OpenOffice Draw + XForms Export + iText = PDF. Das mache ich bei unseren Rechnungen so. Läuft gut. Die Vorlagen erstelle ich mit OO. Weiterer Vorteil: Sekretariat kann selbst das aussehen verändern.
  • Word/Excel/OO/RTF-Templates nutzen, dann in PDF konvertieren. Zum Füllen der Vorlagen gibt es einige (auch open-source) Lösungen, siehe Apache POI, JExelApi, xdocreport, jRTF. Doch dann kommt das Problem: Das in PDF zu konvertieren. Mann kann nun die eigentlichen Programme nutzen und einen PDF-Export mit einem Druckertreiber verwenden, oder das automatisieren. Entweder über Java oder nicht-Java-Programme (etwa der Shell). Im Java-open-source Bereich gibt es hier nach meinem Kenntnisstand nichts wirklich Funktionierendes. Mit OO kann man die UNO-Brücke nutzen, das kappt mit ODT usw. sehr gut, aber man braucht eine Installation und das ist relativ langsam für Massenexports. jOpenDocument Homepage. Open Document library macht das in purem Java, ist aber noch nicht so weit. xdocreport sollte das für Word können, das Resultat ist bei meiner Vorlage aber unbrauchbar. xdocreport kann auch mit FOP -> iText -> PDD arbeiten, das habe ich noch nicht getestet.

Repeating Annotations in Java 8 Build 68 eingezogen

Was das ist: http://openjdk.java.net/jeps/120

In der Klasse Class ist hinzugekommen:

public <A extends Annotation> A[] getAnnotations(Class<A> annotationClass)

public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)

public <A extends Annotation> A[] getDeclaredAnnotations(Class<A> annotationClass)

Und noch ein paar weitere Ergänzungen in Package, System, …

Neu sind ebenfalls ContainerFor und ConainedBy.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7154390, http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/735b93462eed

Buchkritik: The Clean Coder von Robert C. Martin

Ich mag das Buch von Robert Martin (Uncle Bob), weil es offen und ehrlich ist. Selten sagen Entwickler und Berater: „Da habe ich Mist gemacht, ich war blöd, das war dumm“. Robert ist da schonungslos und legt offen, an welchen Stellen er in seinem Leben vor die Wand fuhr. Daraus formuliert er Grundsätze, von denen wir alle lernen können. Dabei ist das Buch relativ untechnisch. Vielmehr steht der Entwickler als Mensch als soziales und mitunter selbstherrliches Wesen im Vordergrund; Coding-Tipps wie Pattern oder Idiome fehlen gänzlich. Aber das ist gut so, denn viel zu oft denken gerade Neueinsteiger, es kommt auf die coole Programmiersprache an, oder Meister der Kommandozeile zu sein. Alles falsch bzw. das ist nur ein Teil. Softwareentwicklung ist ein kollaborativer Prozess. Man muss „Nein“ sagen zu Dingen, die man nicht einhalten kann und ein „Ja“ bedeutet, ein Commitment zu machen, um verlässlich im Team zu arbeiten. So ist auch „Ja“/“Nein“ zu sagen, und die Konsequenzen zu tragen, ein zentraler Bestandteil des Buchs. Weitere Themen sind Zeiteinteilungen, Arbeiten unter Druck und immer wieder, was ein professionellen Entwickler auszeichnet: Testen, Testen, Testen. Da der perfekte professionelle Entwickler nicht geboren, sondern im Laufe der Jahre heranreift, nimmt auch diese Entwicklung im Buch Platz ein. Zentrale Themen bei Martin sind: Programmieraufgaben (was man selbst tun kann) und Mentoring (was die Umgebung/Arbeitgeber tun kann). Wer schön länger im Geschäft ist muss das Buch nicht lesen, denn jeder wird sich dort wiedererkennen; jeder angehende Softwareentwickler sollte das Buch aber lesen und einen Eindruck gewinnen, worauf man sich einlässt und was es heißt, professionell zu arbeiten.

http://www.amazon.de/Clean-Coder-Professional-Programmers-Paperback/dp/B006V37B1G/ref=sr_1_5?s=books&ie=UTF8&qid=1355651332&sr=1-5%20&tag=tutego-21

jdep: Paket-Abhängigkeiten anzeigen, neues Tool für Java 8 in Planung

http://mail.openjdk.java.net/pipermail/core-libs-dev/2012-December/012684.html. Aufruf:

$ jdep -h
Usage: jdeps <options> <files....>
where possible options include:
   -version                 Version information
   -classpath <path>        Specify where to find class files
   -summary                 Print dependency summary only
   -v:class                 Print class-level dependencies
   -v:package               Print package-level dependencies
   -p <package name>        Restrict analysis to classes in this package
                            (may be given multiple times)
   -e <regex>               Restrict analysis to packages matching pattern
                            (-p and -e are exclusive)
   -P  --profile            Show profile or the file containing a package
   -R  --recursive          Traverse all dependencies recursively
   -all                     Process all classes specified in -classpath

$ jdep Notepad.jar Ensemble.jar
Notepad.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\rt.jar
<unnamed> (Notepad.jar)
       -> java.awt
       -> java.awt.event
       -> java.beans
       -> java.io
       -> java.lang
       -> java.net
       -> java.util
       -> java.util.logging
       -> javax.swing
       -> javax.swing.border
       -> javax.swing.event
       -> javax.swing.text
       -> javax.swing.tree
       -> javax.swing.undo

Ensemble.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\jfxrt.jar
Ensemble.jar -> D:\tools\devtools\jdk8\windows-i586\jre\lib\rt.jar
    com.javafx.main (Ensemble.jar)
       -> java.applet
       -> java.awt
       -> java.awt.event
       -> java.io
       -> java.lang
       -> java.lang.reflect
       -> java.net
       -> java.security
       -> java.util
       -> java.util.jar
       -> javax.swing
       -> sun.misc                                 JDK internal API (rt.jar)

Thema der Woche: Servlet-Filter

Was Nordkorea kann, können wir auch. Lies zur Einleitung http://www.spiegel.de/netzwelt/web/html-trick-nordkorea-macht-seinen-fuehrer-groesser-a-872291.html, um eine Idee zu bekommen, was wir vorhaben.

Lege in der IDE ein Web-Projekt an. Setze eine index.jsp in das Wurzelverzeichnis mit Text, der den Namen “Kim Jong Un” enthält (alternativ “Angela Merkel”; je nachdem, wer einem sympathischer ist). Teste die Seite.

Lies http://www.oracle.com/technetwork/java/filters-137243.html und verstehe das Konzept der Filter. Der Code ist mit den Eintragungen in die web.xml nicht mehr ganz aktuell, den letzten Teil kann man daher überspringen.

Kopiere http://www.roseindia.net/java/javaee6/webFilterExample.shtml und probiere es aus. Das Beispiel nutzt die Annotationen aus der aktuellen Servlet-Spezifikation.

Ändere den Filter, so dass er den Namen unseres gewählten Staatsoberhaupts größer setzt. Wie das realisiert ist, ist im Prinzip egal, die einfachster Lösung ist Ok (etwa mit <font size=+1>name</font>).

Java-Versionen gehen mit Unicode-Standard Hand in Hand

In den letzten Jahren hat sich der Unicode-Standard erweitert, und Java ist den Erweiterungen gefolgt.

Java-Version

Unicode-Version

1.0

1.1.5

1.1

2.0

1.1.7

2.1

1.2, 1.3

2.1

1.4

3.0

5

4.0

6

4.0

7

6.0

8

6.2

Java-Versionen und ihr unterstützter Unicode-Standard

Die Java-Versionen von 1.0 bis 1.4 nutzen einen Unicode-Standard, der für jedes Zeichen 16 Bit reserviert. So legt Java jedes Zeichen in 2 Byte ab und ermöglicht die Kodierung von mehr als 65.000 Zeichen aus dem Bereich U+0000 bis U+FFFF. Der Bereich heißt auch BMP (Basic Multilingual Plane). Java 5 unterstützt erstmalig den Unicode 4.0-Standard, der 32 Bit (also 4 Byte) für die Abbildung eines Zeichens nötig macht. Doch mit dem Wechsel auf Unicode 4 wurde nicht die interne Länge für ein Java-Zeichen angehoben, sondern es bleibt dabei, dass ein char 2 Byte groß ist. Das heißt aber auch, dass Zeichen, die größer als 65.536 sind, irgendwie anders kodiert werden müssen. Der Trick ist, ein ein »großes« Unicode-Zeichen aus zwei chars zusammenzusetzen. Dieses Pärchen aus zwei 16-Bit-Zeichen heißt Surrogate-Paar. Sie bilden in der UTF-16-Kodierung ein Unicode 4.0-Zeichen. Diese Surrogate vergrößern den Bereich der Basic Multilingual Plane.

Mit der Einführung von Unicode 4 unter Java 5 gab es an den Klassen für Zeichen- und Zeichenkettenverarbeitung einige Änderungen, sodass etwa eine Methode, die nach einem Zeichen sucht, nun nicht nur mit einem char parametrisiert ist, sondern auch mit int, und der Methode damit auch ein Surrogate-Paar übergeben werden kann. In diesem Buch spielt das aber keine Rolle, da Unicode-Zeichen aus dem höheren Bereichen, etwa für die phönizische Schrift, die im Unicode-Block U+10900 bis U+1091F liegt – also kurz hinter 65536, was durch 2 Byte abbildbar ist –, nur für eine ganz kleine Gruppe von Interessenten wichtig sind.

Statische sum(…)/max(…)/min(…) Methoden in numerischen Wrapper-Klassen

In den numerischen Wrapper-Klassen, also Byte, Short, Integer, Long, Float, Double und auch Character – obwohl Character nicht die Basisklasse Number erweitert – gibt es seit Java 8 je drei neue Methoden: sum(…)/max(…)/min(…), die genau das machen, was der Methodenname verspricht.

final class java.lang.Byte|Short|Integer|Long|Float|Double
extends Number
implements Comparable<Integer>

§ static Typ sum(Typ a, Typ b)
Bildet die Summe zweier Werte und liefert diese zurück. Es entspricht einem einfachen a + b. Die Angabe Typ steht dabei für den entsprechenden primitiven Typ byte short, int, long, float oder double, etwa in int sum(int a, int b).

§ static Typ min(Typ a, Typ b)
Liefert das Minimum der zwei Zahlen.

§ static Typ max(Typ a, Typ b)
Liefert das Maximum der zwei Zahlen.

final class java.lang.Character
implements Comparable<Character>, Serializable

§ static Typ sum(Typ a, Typ b)
Liefert (char)(a + b) zurück.

§ static Typ min(Typ a, Typ b)
Liefert das kleinere der beiden Zeichen bezüglich der Unicode-Position.

§ static Typ max(Typ a, Typ b)
Liefert das größere der beiden Zeichen.

Die Methoden sich für sich genommen nicht spannend. Für die Summe (Addition) tut es genauso gut der +-Operator – er steckt sowieso hinter den sum(…)-Methoden – und so wird keiner auf die Idee kommen i = Integer.sum(i, 1) statt i++ zu schreiben. Für das Maximum/Minimum bietet die Math-Klasse auch schon entsprechende Methoden min(a,b)/max(a,b). Der Grund für diese drei Methoden ist vielmehr, dass sie im Zusammenhang mit Lambda-Ausdrücken interessant sind – dazu später mehr.

Java 8: Division mit Rundung Richtung negativ unendlich

Die Ganzzahldivision in Java ist simpel gestrickt. Vereinfacht ausgedrückt: Konvertiere die Ganzzahlen in Fließkommazahlen, führe die Division durch und schneide alles hinter dem Komma ab. So ergeben zum Beispiel 3 / 2 = 1 und 9 / 2 = 4. Bei negativem Ergebnis, durch entweder negativen Dividenden oder Divisor, das gleiche Spiel: -9 / 2 = -4 und 9 / -2 = -4. Schauen wir uns einmal die Rundungen an.

Ist das Ergebnis einer Division positiv und mit Nachkommaanteil, so wird das Ergebnis durch das Abschneiden der Nachkommastellen ein wenig kleiner, also abgerundet. Wäre 3/2 bei Fließkommazahlen 1,5, ist es bei einer Ganzzahldivision abgerundet 1. Bei negativen Ergebnissen einer Division ist das genau anders herum. Denn durch das Abschneiden der Nachkommastellen wird die Zahl etwas größer. -3/2 ist genau genommen -1,5, aber bei der Ganzzahldivision -1. Doch -1 ist größer als -1,5. Java wendet ein Verfahren an, was gegen null rundet.

In Java 8 hat die Mathe-Klasse zwei neue Methoden bekommen, die bei negativem Ergebnis einer Division nicht gegen null runden, sondern gegen negativ unendlich, also auch in Richtung der kleineren Zahl, wie es bei den positiven Ergebnissen ist.

class java.lang.Math

– static int floorDiv(int x, int y)

– static long floorDiv(long x, long y)

Ganz praktisch heißt das: 4/3 = Math.floorDiv(4, 3) = 1, aber wo -4 / 3 = -1 ergibt, liefert Math.floorDiv(-4, 3) = -2.

Java bekommt unchecked IO-Ausnahmen und BufferedReader.lines()

Die neue Methode BuferedReader lines() liefert ein Stream von Strings, die mit den Bulk-Methoden der Lambda-Bibliothek verarbeitet werden können. Brian Goetz gibt unter http://mail.openjdk.java.net/pipermail/lambda-dev/2012-November/006545.html ein (nicht ganz fehlerfreies) Beispiel:

try (reader = new BR(new FR(file))) {
     reader.lines()
           .filter(e -> !startsWith("#"))
           .map(e -> e.toUpperCase())
           .forEach(...);
}

Der Changeset: ttp://hg.openjdk.java.net/lambda/lambda/jdk/rev/94d64473e8e6

Wie kann ein Java-Compiler in Java implementiert sein?

Der Java-Compiler von Oracle und der Java-Compiler der Entwicklungsumgebung Eclipse sind selbst in Java implementiert und generieren diesen Bytecode (es gibt aber auch Java-Compiler in C++, wie den Jikes-Compiler. Natürlich gibt es da ein Henne-Ein-Problem: wie sollte ein neuer in Java geschriebener Compiler durch Java übersetzt werden? Daher entsteht der erste Compiler immer in einer anderen Sprache, und die übersetzt eine kleine Teilmenge der Zielsprache, und dann wird ein neuer Compiler in der Minisprache entwickelt. Im nächsten Schritt wachsen und vergrößern sich Grammatik und Compiler. In der Sprache der Compilerbauer heißt der Prozess Bootstrapping. Bei Java war das ein Prozess über mehrere Stufen. Patrick Naughton schreibt im Buch The Java handbook dazu: “Arthur van Hoff rewrote the compiler in Oak itself, replacing the C version that James originally wrote.“

Thema der Woche: Thread-Kooperation und Benachrichtigung; Schere, Papier, Stein

Zwei Threads sollen auf ein Signal warten, das von einem dritten Threads jede Sekunde gesendet wird. Kommt das Signal, soll sich der erste und zweite Thread zufällig für Schere, Papier oder Stein entscheiden.

  • Welche Klassen und Datenstrukturen helfen bei der Lösung?
  • Wer wertet bei dem kleinen Spiel aus, wer gewonnen hat? Muss es hier eine weitere Benachrichtigung geben?
  • Implementiere eine Lösung.

Tiefe Objektkopien mit JAXB und JAXBSource

Die unmarshal(…)-Methoden ist überladen mit Parametern, die typische Datenquellen repräsentieren, etwa Dateien oder Eingabeströme wie ein Reader. Allerdings sind noch andere Parametertypen interessant, und es lohnt sich, hier einmal in die API-Dokumentation zu schauen. Ein spannender Typ ist javax.xml.transform.Source, beziehungsweise die Implementierung der Schnittstelle durch JAXBSource. JAXBSource ist die Quelle, aus denen JAXB seine Informationen bezieht, um ein neues Java-Objekt zu rekonstruieren.

Das nächste Beispiel nimmt sich ein Objekt room als Basis und erzeugt eine tiefe Kopie davon:

Room room = …

JAXBContext context = JAXBContext.newInstance( Room.class );

Unmarshaller unmarshaller = context.createUnmarshaller();

JAXBSource source = new JAXBSource( context, room );

Room copiedRoom = Room.class.cast( unmarshaller.unmarshal( source ) );

System.out.println( copiedRoom.getPlayers() ); // [com.tutego.insel.xml.jaxb.Player@…]

Das Beispiel zeigt somit, wie sich mit Hilfe von JAXB Objektkopien erzeugen lassen.