How to put files in a ZIP file with NIO.2

URI p = Paths.get( "c:/Users/Christian/Dropbox/jokes.zip" ).toUri();
URI uri = URI.create( "jar:" + p );

Map<String, String> env = new HashMap<>();
env.put( "create", "true" );
try ( FileSystem zipfs = FileSystems.newFileSystem( uri, env ) ) {
  Files.write( zipfs.getPath( "/j1.txt" ), "The truth is out there. Anybody got the URL?".getBytes() );
  Files.write( zipfs.getPath( "/j2.txt" ), "The more I C, the less I see.".getBytes() );
}

gzip Kommandozeilenprogramm mit wenigen Zeilen Quellcode

package com.tutego.insel.io.zip;

import java.io.*;
import java.nio.file.*;
import java.util.zip.GZIPOutputStream;

public class gzip {

  public static void main( String[] args ) {
    if ( args.length != 1 ) {
      System.err.println( "Benutzung: gzip <source>" );
      return;
    }

    try ( OutputStream gos = new GZIPOutputStream( Files.newOutputStream( Paths.get( args[ 0 ] + ".gz" ) ) ) ) {
      Files.copy( Paths.get( args[ 0 ] ), gos );
    }
    catch ( IOException e ) {
      System.err.println( "Fehler: Kann nicht packen " + args[ 0 ] );
    }
  }
}

Diagnose Kommandos kommen in Java 8 und Java 7u4

Das werden wir im nächsten Build bekommen, Quellen schon mal hier: http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/0194fe5ca404.

A diagnostic command is an action that can be invoked dynamically mainly for troubleshooting and diagnosis.

Die Idee ist also, das man ein Kommandozeilentool jcmd hat, mit dem man Kommandos an die JVM schicken kann. Dabei sind unterschiedliche Kommandos vordefiniert. Mit dem Argument PerfCounter.perf werden Performance-Kenngrößen ausgegeben.

NetBeans 7.1 Code-Transformation nach Java 7

Wähle im Menü Refactor > Inspect and Transform … und dann im Dialog bei Use:/Configuration: den Eintrag Convert to Java 7 aus. Ein Klick auf Inspect startet die Suche und listet Änderungsmöglichkeiten auf und bietet an, die Stellen automatisch zu beheben.

Ich habe das Tool auf den Beispielen meines Buches angewendet und die meisten Hinweise beziehen sich auf Diamond und natürlich im IO-Kapitel auf auf try-mit-Ressourcen. Damit habe ich heute den ganzen Tag verbracht und auch noch ein paar kleine Fehler gefunden. Eine Stelle ist interessant:

XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter( new FileOutputStream( "writenParty.xml" ) );

XMLStreamWriter hat close() aber kein AutoCloseable. Kann man als Fehler ansehen.

Das hier formt der Konverter nicht um, er beginnt erst bei “fett” mit dem switch, das liegt am zweiten if, was nicht als if else formuliert ist.

if ( "Ende".equals(e.getActionCommand()) )
  System.exit( 0 );
if ( "fett".equals(e.getActionCommand()) )
  t.setFont( font = font.deriveFont( font.getStyle() ^ Font.BOLD ) );
else if ( "kursiv".equals(e.getActionCommand()) )
  t.setFont( font = font.deriveFont( font.getStyle() ^ Font.ITALIC ) );

Java™ Platform, Standard Edition 7 Update 2 Binary Snapshot Releases

http://jdk7.java.net/download.html

Änderungen:

http://hg.openjdk.java.net/jdk7u/jdk7u/ws-b02-2011-08-12_39

Changeset

Bug ID

Synopsys

831f1dadcc35

7057705

can’t generate api docs for JDK7 updates

http://hg.openjdk.java.net/jdk7u/jdk7u/jdk

Changeset

Bug ID

Synopsys

f01230bea4aa

7043737

klist does not detect non-existing keytab

9847e43556fb

7029903

Splash screen is not shown in 64-bit Linux with 16-bit color depth

175f98d43a12

7062969

java -help still shows http://java.sun.com/javase/reference

440d5a3cfdf8

7067922

(launcher) java -jar throws NPE if JAR file does not contain Main-Class attribute

a5ea1f537169

7039182

PPC: NIO: java.io.IOException: Invalid argument in sun.nio.ch.FileDispatcherImpl.read0

http://hg.openjdk.java.net/jdk7u/jdk7u/langtools

Changeset

Bug ID

Synopsys

ceb7ca04b7eb

7060926

Attr.PostAttrAnalyzer misses a case

2f2ac80b6836

7061125

Proposed javac argument processing performance improvement

130154dbafc8

7068902

(javac) allow enabling or disabling of String folding

8b6f8a4bc8b8

7060642

(javadoc) improve performance on accessing inlinedTags

fda5571c663a

6735320

StringIndexOutOfBoundsException for empty @serialField tag

add40922e84d

7059905

(javadoc) promote method visibility for netbeans usage

c’t Artikel über Java 7: “Was lange währt …” – eine kurze Nachkritik

In der c’t hat Michael Tamm in der Ausgabe 17 (August) einen Beitrag über Java 7 geschrieben. Der ist ganz gut gelungen und gibt einen netten Einblick in die Neuerungen von Java 7 (präzisiertes rethrow hat er irgendwie verschwiegen, weiß nicht warum).

Ein paar Kleinigkeiten kann man noch anfügen:

  • Bei switch mit Strings: “Für jeden case-Zweig wird die in der switch-Anweisung aufgeführte String-Variable mit Hilfe ihrer Methode equals() mit der Konstanten hinter case verglichen”. Hier könnte man meinen, dass eine switch-Anweisung zu einer if-else-Kaskade mit einer linearen Laufzeit führt. Das stimmt aber nicht. equals() kommt erst relativ spät dazu. Erst gibt es einen switch auf dem Hashwert, wenn der passt, kommt equals(), um mit Hashwert-Kollisionen umzugehen.
  • “… dass man beim Anlegen von Objekten mit generischen Parametern diese auf der rechten Seiten der Zuweisung nicht mehr wiederholen muss…”. Das könnte man so lesen, dass <> ausschließlich bei Zuweisungen oder Initialisierungen gültig ist. Doch <> ist flexibler; es kann durchaus return new ArrayList<>(); heißen. (Dass der Begriff “generischer Parameter” unsauber ist, ist eine andere Sache … )
  • Die Einleitung vom multi-catch beginnt mit “… Seit Java 1.0 gibt es geprüfte (checked exceptions), die immer behandelt oder in der Methodensignatur aufgeführt werden müssen, sowie die ungeprüfte Ausnahmen […].“ Ob multi-catch nun checked oder unchecked Exception fängt ist egal, daher ist die Information an diese Stelle eigentlich überflüssig.
  • Beim Thema try-mit-Ressourcen “Die VM schließt alle hinter dem try in runden Klammern aufgeführten Ressourcen[…]”. Irgendwie macht alles schon die JVM, aber man könnte den Eindruck bekommen, hier ist Magie im Spiel. Das stimmt aber nicht, denn der Compiler erzeugt nur etwas, was wir hätten auch schreiben können, nur haben wir mit dem neuen try weniger Schreibarbeit. Die JVM weiß nicht, ob der tolle Schließ-Code von uns kommt oder nicht.
  • “Das Pendant zur alten Klasse File ist die neue Klasse Path”. Pendant? Klingt, als ob die gleich sind, ist aber absolut nicht so. Wenn das ein Pendant, also eine Kopie wäre, warum dann NIO.2?

Die beschriebenen Dinge sind nur missverständlich, aber leider gibt es auch zwei dickere Falschaussagen:

  • “Mit den in Java 7 eingeführten Typannotationen lassen sich nun auch Typen näher beschreiben”. Es folgt das Beispiel “@NonNull Set<@NonNull Edges> edges;” und er verweist auf den Link von JSR-308 (http://types.cs.washington.edu/jsr308/). Wäre nett, ist aber Blödsinn! Es gibt in Java 7 keine Änderung. Das verlinkten Dokument sagt: “Type annotations are planned to be part of the Java language and are supported by Oracle’s OpenJDK (for JDK 7, as of build M4).” Das JST-308 nicht von Java 7 ist hatte ich auch schon vor einem halben Jahr geschrieben: http://www.tutego.de/blog/javainsel/2011/02/java-se-7-developer-preview-release-verfgbar/, aber ich erwarte nicht, dass Herr Tamm mein Blog liest.
  • “[…] Nimbus Look & Feel […] ist standardmäßig aktiv”. Hätte Michael nur ein Swing-Programm gestartet, wäre ihm aufgefallen, das immer noch Metal aktiv ist und nicht Nimbus. (Grund: Inkompatibilitäten http://blogs.oracle.com/henrik/entry/nimbus_look-and-feel_in_jdk_7). Das SwingSet Demo wählt nur automatisch Nimbus aus.

Bug des Tages im Java-Compiler: case

package insel;

public class Insel {

    public static void main(String[] args) {

        switch (1) {
            case (1):
        }
        switch ("") {
            case (""):
        }

    }
}

Eclipse und NetBeans kommen damit zurecht, nicht aber javac. Der Fehler ist bekannt und für das nächste Update gefixt.

An exception has occurred in the compiler (1.7.0). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java.lang.NullPointerException
    at com.sun.tools.javac.comp.Lower.visitStringSwitch(Lower.java:3456)
    at com.sun.tools.javac.comp.Lower.visitSwitch(Lower.java:3357)
    at com.sun.tools.javac.tree.JCTree$JCSwitch.accept(JCTree.java:959)
    at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:58)
    at com.sun.tools.javac.comp.Lower.translate(Lower.java:2160)

NIO.2 Umstellung. Mein Fazit (nach einem Tag)

Um zu testen, wie sich die neue NIO.2-Bibliothek so in der Praxis macht, habe ich unsere tutego-Software auf NIO.2 gebracht. Als erstes habe ich File durch Path/Paths/Files-Aufrufe ersetzt. Dabei sind mir schon ein paar Stellen aufgefallen, die ich gerne noch verbessert sehen würde für >= Java 8.

  1. Von den File-Konstrukturen gibt es: File(File parent, String child) und File(String parent, String child). Es ist praktisch, dass der erste Teil entweder File oder String sein kann. Ich habe bei mir eine Menge von Aufrufen der Art new File(path, filename). Mal ist path ein String, mal ein File (in der Regel File). Bei der Konvertierung zu Path wird es ungemütlich, denn es gibt nur get(String first, String… more) aber kein get(Path first, String… more). Also läuft es auf ein path.resove(child) raus, was ich aber nicht so schön finde wie ein get(path, child). Aber alles Geschmacksache.
  2. File wird öfter als Parametertyp akzeptiert als Path. So muss ich schreiben:
    PrintWriter out = new PrintWriter( testimonalsPath.toFile() );
    Schöner wäre ein Konstruktur PrintWriter(Path).
  3. Die Methode getFileName() liefert keinen String, sondern ein Path-Objekt nur mit dem Dateinamen. Daher führt folgendes nicht zum Ziel: path.getFileName().endsWith(".xml"). Und path.getFileName().toString()endsWith(".xml") ist etwas lang.
  4. Files.readAllBytes() ist zwar schön, aber Files.readAllChars(Path,CharSet) wäre auch nett.

JDK 7 ist da … und schon gleich die ersten Probleme

Am 7.7 wurde Java 7 ja schon weltweit gefeiert wir eine neue CD von Justin Biber. Heute ist der 28.07. und damit das offizielle Release-Datum. Eigentlich läuft das ganz rund, ABER mit HotSpot gibt es einen richtig harten Fehler: http://www.lucidimagination.com/search/document/1a0d3986e48a9348/warning_index_corruption_and_crashes_in_apache_lucene_core_apache_solr_with_java_7. Tja, dumm gelaufen.

Enumerate every new type and attribute in Java 7 API with a homebrewed doclet

This doclet searchs for “@since 1.7” and reports the places. Dont forget to put JDK/lib/tools.jar in the classpath.

package com.tutego.tools.javadoc;

import java.io.*;
import java.util.Formatter;
import com.sun.javadoc.*;
import com.sun.tools.javadoc.Main;

public class SinceJava7FinderDoclet
{
  private final static Formatter formatter = new Formatter();

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

  private static void processClass( ClassDoc clazz )
  {
    for ( Tag tag : clazz.tags( "since" ) )
      if ( "1.7".equals( tag.text() ) )
          formatter.format( "Neuer Typ %s%n", clazz );

    for ( MethodDoc method : clazz.methods() )
      for ( Tag tag : method.tags( "since" ) )
        if ( "1.7".equals( tag.text() ) )
          formatter.format( "Neue Methode %s%n", method );

    for ( ConstructorDoc constructor : clazz.constructors() )
      for ( Tag tag : constructor.tags( "since" ) )
        if ( "1.7".equals( tag.text() ) )
          formatter.format( "Neuer Konstruktor %s%n", constructor );

    for ( FieldDoc field : clazz.fields() )
      for ( Tag tag : field.tags( "since" ) )
        if ( "1.7".equals( tag.text() ) )
          formatter.format( "Neues Attribut %s%n", field );
  }

  public static void main( String[] args )
  {
    PrintStream err = System.err, out = System.out;
    System.setErr( new PrintStream( new OutputStream() {
      @Override public void write( int b ) { }
    } ) );
    System.setOut( System.err );

    String[] params = { "-quiet", // ignored!?
                        "-doclet", SinceJava7FinderDoclet.class.getName(),
                        "-sourcepath", "C:/Program Files/Java/jdk1.7.0/src/",
//                        "java.lang"
                        "-subpackages", "java:javax"
                        };
    Main.execute( params );

    System.setErr( err );
    System.setOut( out );

    System.out.println( formatter );
  }
}

The result:

Weiterlesen

Java 7 RC1 ist da

Build 147 bildet den ersten Release Kandidaten wie http://mreinhold.org/blog/jdk7-rc berichtet. Dann mal schnell die neue Version besorgen (http://jdk7.java.net/download.html) und alles testen! Mein anfänglichen Probleme mit irgendwelchen internen Sortierproblemen in der Collection-API sind auch nicht mehr aufgetreten. Für mich läuft Java 7 damit ohne Probleme.

Für die 10. Auflage der Insel muss ich eigentlich nur noch mein Kapitel über ARM-Blöcke schreiben, sonst ist die Auflage für den Band 1 soweit fertig.

Hinweis:

Java 7 gut in der Zeit

Nach dem Beitrag von http://mail.openjdk.java.net/pipermail/jdk7-dev/2011-May/002124.html und dem Kalender http://openjdk.java.net/projects/jdk7/ kann man sagen, dass das JDK-Team gut in der Zeit liegt und Java 7 vermutlich punktgenau am 28.7.2011 landen wird.

2010/12/23    Feature Complete (M11)
2011/02/17    Developer Preview (M12)
2011/04/12    Rampdown start: P1-P3 bugs only
2011/04/28    API/interface changes: Showstoppers only
2011/05/11    All targeted bugs addressed
2011/05/18    Bug fixes: Showstoppers only
2011/06/02    Last scheduled build (M13)
Final test cycle starts
2011/07/28    General Availability

Allerdings führt http://mail.openjdk.java.net/pipermail/jdk7-dev/2011-May/002124.html auch auf:

  - The Gervill sound synthesizer was integrated early in JDK 7 but
    due to a clerical error never made it onto the feature list; and

  - The "Enhanced JMX Agent and MBeans" feature has been reduced to
    "Enhanced MBeans"; the JMX Agent work was not completed in time.