null/NullPointerException in anderen Programmiersprachen: Ruby, nil, Scala, Option, None, Some

Ist Java eine pure objektorientiere Programmiersprache? Nein, da Java einen Unterschied zwischen primitiven Typen und Referenztypen macht. Nehmen wir für einen Moment an, dass es primitive Typen nicht gibt. Wäre Java dann eine reine objektorientierte Programmiersprache, bei der jede Referenz ein pures Objekt referenziert? Die Antwort ist immer noch nein, da es mit null etwas gibt, mit dem Referenzvariablen initialisiert werden können, aber was kein Objekt repräsentiert und keine Methoden besitzt. Und das kann bei der Dereferenzierung eine NullPointerException geben.

Neue Programmiersprachen gehen da etwas andere Wege und null-Referenzierungen sind nicht möglich. In der Sprache Ruby zum Beispiel ist immer alles ein Objekt. Wo Java mit null ein „nicht belegt“ ausdrückt, macht das Ruby mit nil. Der feine Unterschied ist, dass nil ein Exemplar der Klasse NilClass ist, genau genommen ein Singleton, was es im System nur einmal gibt. nil hat auch ein paar öffentliche Methoden wie to_s (wie Javas toString()), was dann einen leeren String liefert. Mit nil gibt es keine NullPointerException mehr, aber natürlich immer noch einen Fehler, wenn auf diesem Objekt vom Typ NilClass eine Methode aufgerufen wird, die es nicht gibt.

In Objective-C, der Standardsprache für iPhone-Programme, gibt es das Null-Objekt nil. Üblicherweise passiert nicht, wenn eine Nachricht an das nil-Objekt gesendet wird; die Nachricht wird einfach ignoriert.[1] Es gibt Programmiersprachen, die noch etwas anders an das null-Problem herangehen. Bei der JVM-Sprache Scala gibt es für den Wert null einen eigenen Typ, nämlich Null. (Null erbt von AnyRef – was wiederum von Any erbt, dem absoluten Basistyp – und Null hat sogar mit Nothing einen Untertyp). Allerdings wird Scalas null nicht so wie Rubys null genutzt sondern entspricht Java null: Der Versuch, eine genullte Variable zu dereferenzieren, führt zu einer NullPointerException. Anders gesagt: Scala führt für null einen Typ ein, aber eine NullPointerException ist immer noch nicht passé. Statt aber in Scala null zurückzugeben, nutzen Programmierer etwas anderes: eine Option. Die Klasse Option repräsentiert optionale Werte und kommt in zwei Ausprägungen: Some und None (entspricht Rubys nil). Statt dass wie in Java eine Methoden eine Referenz direkt zurückgibt, geben Scala-Methoden etwas vom Typ Option zurück, und das heißt, entweder ein None- oder Some-Objekt. Das Some-Objekt ist ein Behälter und speichert die eigentliche Referenz. Eine Methode mit Option-Rückgabe sieht etwa so aus: if ( WertUngleichNull ) Some(Wert) else None. Mit dem parametrisierten Konstruktor Some(Wert) kommt der Wert in das Some-Objekt. Empfängt der Aufrufer die Rückgabe, kann er am Typ erkennen, ob die Operation erfolgreich war oder nicht. Das ist jedoch nicht, wie eine Option üblicherweise in Scala eingesetzt wird. Denn Option-Objekte (und somit Some oder None) besitzen eine Methode getOrElse(), sodass sich für eine Rückgabe result vom Typ Option schreiben lässt: result.getOrElse(alternativerWert). Repräsentiert result ein Some-Objekt, so liefert die Implementierung von getOrElse() den gespeicherten Wert, ist es None, so liefert die Implementierung das Argument als Rückgabe. Spontan hört sich das jetzt noch nicht so wahnsinnig innovativ an, aber interessant wird die Option durch die Tatsache, dass Scala sie an verschiedenen Stellen intern in den Klassenbibliotheken einsetzt. Das liegt dran, dass die Option-Klasse an die 30 Methoden deklariert und viele der Methoden etwa bei Operationen auf Datenstrukturen aufgerufen werden. Wenn zum Beispiel auf allen Elementen der Liste eine Transformation durchgeführt werden soll, und ein None-Objekt befindet sich in der Liste, passiert beim Aufruf der Transformationsmethoden auf dem None-Objekt nichts, denn dort ist die Implementierung einfach leer.


[1] Es gibt auch Compiler wie der GCC, der mit der Option -fno-nil-receivers dieses Verhalten abschaltet, um schnellere Maschinencode zu erzeugen. Denn letztendlich muss in Maschinencode immer ein Test stehen, der auf 0 prüft.

Erinnerung: iText ist Affero GPL Lizenz

Von Wikipedia:

In the end of 2009, iText version 5 is released under Affero GPL license. This license is drastically different from the previous license that iText had been

distributed under, in that it requires anyone using iText 5 under a free license to provide the users with the full source of their application. Projects that do not want to provide their source code are required to purchase a commercial license for a non-disclosed price or they cannot upgrade to iText 5. (Projects can continue using previous versions of iText under the more liberal license without any changes.)

Siehe auch:

Sieben XStream Tipps

1. XML-Prolog schreiben

Das kann XStream nicht, aber beim Lesen wird der XML-Prolog überlesen. Man muss den Prolog also von Hand in den Strom schreiben:

Writer w = new OutputStreamWriter(
new BufferedOutputStream(
new FileOutputStream( file ) ), „utf-8“ );
w.write( „<?xml version=\“1.0\“ encoding=\“utf-8\“?>\n“ );
xstream.toXML( value, w );
w.close();

2. Statt voll qualifizierte Klassenamen kann ein anderer Name mit alias() auf dem XStream-Objekt gesetzt werden.

xstream.alias( „Course“, Course.class );
xstream.alias( „Contact“, Contact.class );

3. Statt geschachtelte Elemente sollen gewisse Dinge in Attributen stehen:

xstream.useAttributeFor( TrainerCourse.class, „price“ );
xstream.useAttributeFor( TrainerCourse.class, „languages“ );

4. Statt Elemente von Sammlungen in ein eigenes Container-Element zu setzen, kann das auch ohne Überelement gesetzt werden:

xstream.addImplicitCollection( Trainer.class, „trainerCourses“ );

5. Gewisse Dinge sollen anders geschrieben werden. Konverter sind angebracht:

xstream.registerConverter( new TrainerCourseConverter() );
xstream.registerConverter( new YYYYMMDDConverter() );

Konverter können ganz eigenständig entwickelt werden (1. Bsp.), oder eine Basisklasse (2. Bsp.) vereinfacht das:

class TrainerCourseConverter implements Converter
{
@Override
public void marshal( Object value, HierarchicalStreamWriter writer, MarshallingContext arg2 )
{
TrainerCourse tc = (TrainerCourse) value;
writer.addAttribute( „courseCode“, c.getCourseCode() );
}

@Override
public Object unmarshal( HierarchicalStreamReader arg0, UnmarshallingContext arg1 )
{

}

@SuppressWarnings( „unchecked“ )
@Override
public boolean canConvert( Class clazz  )
{
return clazz.equals( TrainerCourse.class );
}
}

Zweiter einfacher Konverter:

class YYYYMMDDConverter extends AbstractSingleValueConverter
{
@SuppressWarnings( „unchecked“ )
public boolean canConvert( Class clazz )
{
return clazz.equals( Date.class );
}

@Override
public Object fromString( String str )
{
return StringUtils2.isEmpty( str ) ? null : DateUtils.parseDDMMYYYY( str );
}

@Override
public String toString( Object obj )
{
return obj == null ? „“ : DateUtils.formatDDMMYY( (Date) obj );
}
}

6. Elemente mit bekannten Namen sollen in einer CDATA-Umgebung geschrieben werden:

xstream = new XStream( new XppDriver() {
public HierarchicalStreamWriter createWriter( Writer out ) {
return new PrettyPrintWriter( out ) {
boolean isCDATA = false;
@SuppressWarnings( „unchecked“ ) @Override public void startNode( String name, Class clazz ) {
super.startNode( name, clazz );
isCDATA = name.equals( „contents“ ) || name.equals( „description“ );
}
@Override protected void writeText( QuickWriter writer, String text ) {
if ( isCDATA ) { writer.write( „<![CDATA[\n“ ); writer.write( text ); writer.write( „\n]]>“ ); }
else super.writeText( writer, text );
}
};
}
} );

7. XStream soll XML-Dateien selbst laden und speichern (http://xstream.codehaus.org/persistence-tutorial.html)

Verwaltet man viele kleine XML-Dokumenten, etwa Kontakte, kann XStream diese XML-Kontakt-Dateien automatisch anlegen, lesen und aktualisieren. Der Tick ist, dass man alle Daten in eine spezielle Map, Set oder List setzt. Die XStream-Implementierungen der add(), put(), get(), … Methoden sind so realisiert, dass die Daten beim add()/put() in die Datenstruktur und gleichzeitig XML-serialisiert als Datei ins Dateisystem kommen. In welches Verzeichnis sagt die FilePersistenceStrategy.

PersistenceStrategy strategy = new FilePersistenceStrategy(new File(„/tmp“));
Map  map= new XmlMap( strategy );

Die Dateinamen sind etwas merkwürdig, etwa long@12345676, aber dass ist kein Wunder, denn der Dateiname kodiert den Schlüssel, denn XStream muss ja bei einem get() etwa die XML-Datei wiederfinden.

Neue Spezifikation von ARM-Blöcken in Java 7

http://blogs.sun.com/darcy/entry/project_coin_updated_arm_spec

Das ganze ließt sich jetzt schon wie ein Text aus der JLS. (Was im Übrigen für einige andere Neuerungen in Java 7 noch aussteht.)

Apropos: Collection-Litarale sehe ich immer noch nicht, und es gibt ganz schön Haue bei den Closures. Bis September ist nicht mehr viel Zeit. Unterstriche in große Zahlen soll ja wohl nicht alles gewesen sein…

Heise mobil gibt Überblick über 11 Android Smartphones

Unter http://www.heise.de/mobil/artikel/Elf-Smartphones-mit-Android-ab-160-Euro-1026810.html. Unter Anderem:

  1. Acer beTouch E110
  2. Google Nexus One
  3. HTC Desire
  4. HTC Legend
  5. LG GT540
  6. LG GW620
  7. Motorola Backflip
  8. Motorola Milestone
  9. Samsung I5700 Galaxy Spica
  10. Sony Ericsson Xperia X10
  11. Sony Ericsson Xperia X10 mini

Für Android-Schulungen siehe http://www.tutego.de/seminare/java-schulung/Android-Schulung-Google-Android-Kurs.html.

Android-Anwendungen zusammenklicken

http://appinventor.googlelabs.com/about/ schreibt heute von einer Möglichkeit, Android-Apps zuzusammenzuklicken:

 

 

 

Die Musik ist eigentlich am Besten…

Das ganze ist noch nicht für alle – eine Voranmeldung ist nötig.

Der App Builder nutzt unter anderen:

The blocks editor uses the Open Blocks Java library for creating visual blocks programming languages. Open Blocks is distributed by the Massachusetts Institute of Technology’s Scheller Teacher Education Program and derives from thesis research by Ricarose Roque. We thank Eric Klopfer and Daniel Wendel of the Scheller Program for making Open Blocks available and for their help in working with it. Open Blocks visual programming is closely related to the Scratch programming language, a project of the MIT Media Laboratory’s Lifelong Kindergarten Group.

The compiler that translates the visual blocks language for implementation on Android uses the Kawa Language Framework and Kawa’s dialect of the Scheme programming language, developed by Per Bothner and distributed as part of the Gnu Operating System by the Free Software Foundation.

Buchkritik: Java Extreme Programming Cookbook

Eric M. Burke, Brian M. Coyner. O’Reilly. ISBN 0-596-00387-0. März 2003. 288 Seiten

Viele XP-Bücher konzentrieren sich auf die „menschliche“ Seite der XP-Entwicklung, aber nicht auf die Tools, die bei der XP-Entwicklung einen großen Stellewert einnehmen. Diese Lücke versucht das Buch mit einer Vorstellung der Tools und Technologien zu füllen, die Anfang 2000 von Bedeutung waren: EJB 2, JUnit 3, CVS. Dumm ist nur, dass die Technologien und Tools heute an Bedeutung verloren haben und durch neuere Produkte ersetzt wurden, sodass auch das Buch heute nicht mehr sonderlich spannend ist und als veraltet gelten kann. Java EE 5 (bzw. Java EE 6) ersetzen für Enterprise-Produkte die J2EE 1.4, JUnit 3 ersetzt heute JUnit 4, Cactus (http://jakarta.apache.org/cactus/) wird nicht mehr weiterentwickelt, und Subversion ersetzt CVS. Für ein Buch, das es nicht nur bei den Konzepten belässt, sondern auch technisch tiefer geht ein Problem. Weiterhin ist die ausschließliche Betrachtung von Open Source etwas einschränkend. (Und der Titel des Buches ist nicht „Java XP Programming Cookbook with Open Source Tools“!) Es ist zwar toll, dass Open-Source Produkte nichts kosten und auch sehr verbreitet sind, aber Hersteller wie Atlassian bieten sehr gute Projekte, die bei der XP-Entwicklung helfen. Weiterhin fehlen in meinen Augen einige zentrale Tools, und es reicht nicht, XP auf Ant, JUnit (zzgl. HttpUnit, JUnitPerf), Mocking, XDoclet zu beschränken. Hier gibt es bessere Bücher. Februar 2009

jRTF = a new library for building RTF documents

jRTF is a simple library to generate RTF documents and to fill RTF template files. The syntax is compact and non-verbose which makes it to some kind of DSL for RTF documents. Its under the BSD license.

The Basics

Write a simple RTF document to a file:

Rtf.rtf().p( "Hello World" ).out( new FileWriter("out.rtf") );

Special RTF-characters like "{", "}", "\" are encoded automatically. "\t" will stay tab and "\n" will be converted to a new paragraph.

The static document() creates a new RTF document object and the p() method is short for "paragraph". The out() method finally writes the output to an Appendable (a Writer for example) and out() without arguments or toString() returns the RTF document as String. The p()method is quite flexible because you add as many parameters as you like. If during building or writing of the file some exceptions will occur they are all of type RtfException which itself is a RuntimeException. So I/O errors during writing will be wrapped in this RtfException.

Because jRTF makes heavy use of statics methods the programs can be very concise and compact with static imports. Let’s assume the following (static) imports for the next examples:

import static com.tutego.jrtf.Rtf.rtf;
import static com.tutego.jrtf.RtfDocfmt.*;
import static com.tutego.jrtf.RtfHeader.*;
import static com.tutego.jrtf.RtfInfo.*;
import static com.tutego.jrtf.RtfFields.*;
import static com.tutego.jrtf.RtfPara.*;
import static com.tutego.jrtf.RtfSectionFormatAndHeaderFooter.*;
import static com.tutego.jrtf.RtfText.*;
import static com.tutego.jrtf.RtfUnit.*;

Sections

A RTF document consists of paragraphs which itself are collected in sections. A section is some kind of mini document with own header, footer, margins, columns. Most documents consist of only one section.

The p() method of the Rtf class is just a façade for the following

rtf().section( p( "Hello World" ) ).out( new FileWriter("out.rtf") );

If there will be more sections they are accumulated this way:

rtf().section(xx).section(xx).section(xx).out(xx);

Paragraphs and Formattings

The following RTF document consists of several paragraphs and text formattings:

rtf().section(
   p( "first paragraph" ),
   p( tab(),
      "second par",
      bold( "with something in bold" ),
      text( "and" ),
      italic( underline( "italic underline" ) )    
    ) 
).out( out );

The declaration of the section method is:

  • Rtf section(RtfPara... paragraphs)

For building paragraphs the RtfPara class offers two useful static methods: p(RtfText...) and a convenience method p(Object...). So you either build a paragraph with a collection of RtfText objects or you pass a sequence of objects which will be converted to Strings (if the type is not already RtfText). null elements in the sequence will be ignored.

A String can be wrapped in a RtfText object via the static method text(String) of the RtfText class. There is also the vararg methodtext(Object...) with is the foundation for p(Object...).

Beside of using ordinary text there are a couple of special methods like tab(), bullet(), currentDateAbbreviated(), shortHyphen() and more.

Special Text and Pictures

A footnote (rtf() omitted for brevity):

p( text("Read this book"),
   footnote( "The joy of RTF" ),
   text(".") )

Using a field requires two text blocks: One for the format description and one for a value a reader can show (most recent calculated result of the field).

field( p("time \\@ \"dd.MM.yyyy\""),
       p("20.06.2010") )

Because there are so many different fields and time is a common case there is an extra class RtfFields with static utility methods. Insert a time field with a pattern like this: timeField("hh:mm:ss"). Or the number of pages for a header:

p( pageNumberField(), "von", sectionPagesField() )

Pictures are part of a paragraph. The source is given by an URL or InputStream. If the resource is not available a RtfException will be thrown during writing.

p( picture( getClass().getResource( "folder.png" ) )
   .size( 64, 64, PIXEL )
   .type( AUTOMATIC )
)

You can explicitly set the picture type to PNG or JPEG, but usually PictureType.AUTOMATIC will do the job.

Paragraph Formatting

It you want a paragraph with bullets at the beginning use ul() instead of p():

section(
  p( "first paragraph" ),
  ul( "bullet1"),
  ul( "bullet2"),
  p( "another paragraph" )
)

The p() methods return an RtfTextPara object which allows formatting the paragraph according to the builder pattern. Aligning a paragraph is done this way;

p( text("centered and indented") ).alignCentered().indentFirstLine( 0.25, RtfUnit.CM )

RtfUnit is an enum. RTF uses a quite unique measurement (twips) but with the enum there is no need to know anything about twips.

If you want to use tabs do this:

p( "1\t2\t3" ).tab( 3, CM )
              .tab( TabKind.CENTER, TabLead.DOTS, 9, CM )

Additional to p() there is a method pard() where the paragraph styles are not inherited to the following paragraph.

Tables

Tables are a bit tricky in RTF because there isn’t a concept of a table but just the concept of a row. In total a section can contain two different types of blocks: paragraphs and rows. While p() lets you insert a regular paragraph the method row() lets you insert a row.

p( "lala" ),
row( "Number", "Square" ),
row( 1, 1 ),
row( 2, 4 ),
p( "lulu" )

While the result type of p() is RtfTextPara the result type of row() is RtfRow. With RtfRow you style the hole row in a similar way you style the paragraph.

row(
  bold( "S" ), bold( "T" )
).bottomCellBorder().topCellBorder().cellSpace( 1, CM ),
row(
  "Good", "nice"
). cellSpace( 1, CM )

A Bit of Style

In order to use different fonts and colors a header has to precede the section:

rtf()
  .header(
    color( 0xff, 0, 0 ).at( 0 ),
    color( 0, 0xff, 0 ).at( 1 ),
    color( 0, 0, 0xff ).at( 2 ),
    font( "Calibri" ).at( 0 ) )
  .section(
        p( font( 1, "Second paragraph" ) ),
        p( color( 1, "green" ) )
  )
).out( out );

This header is setting 3 colors and one font. Every color and font is identified by an index. This index is used later to identify this color and font. The numbering starts with 0. If there is no font given, Times will be the default font at position 0.

Some formats and styles are bound to a section, like a header. Let’s set a header for all pages in that section:

section(
  headerOnAllPages(
    p( "Date:", currentDate() )
  ),
  p( "bla bla bla " )
)

Metadata (Info, Document Formattings)

A RTF document can have some associated meta data: in a header, info or document info block. You can set this on the rtf() object:

rtf()
  .info( author("christian"), title("without parental guidance") )
  .documentFormatting( defaultTab( 1, CM ),
                       revisionMarking() )
  .section("")
  .out( out );

Templating with jRTF

jRTF is not able to read and change existing RTF documents (also I encourage programmers to extend jRTF) but you can inject RtfTExt in slots. To do so prepare a RTF document and define "variables" with are framed in %%. If for example an address has to be written in in the RTF document put a definition like

%%ADDRESSLINE1%%

in the regular text. (Take care not to change the formattings in between. If jRTF is not substituting your variable open the RTF file and check if the variable is really in the format %%VARIABBLE%%.)

To substitute use the following jRTF API:

Rtf.template( new FileInputStream("template.rtf) )
   .inject( "ADDRESSLINE1", "tutego" )
   .inject( "ADDRESSLINE2", bold("Sonsbeck") )
   .out( FileOutputStream("out.rtf") );

The key is always of type String but the value argument for inject() goes to RtfText.text(Object). That means regular Strings or formatted RTF text is both fine.

jRTF Design Decisions

Several facts drove the design of jRTF.

  1. The main design of the API was driven by ease of use. Take a paragraph and text for example. They are represented by the classes RtfPara andRtfText. But most methods are overloaded and as an alternative to RtfPara/RtfText they simply accept a regular String for the common usage or even an sequence of objects with are gracefully converted.
  2. jRTF is able to run on the Google App Engine because classes like Color, Font, FileWriter and other black-listed classes aren’t used.
  3. It should not be possible to generate illegal RTF and the library should throw exceptions if strange things happen. (It could do better…)
  4. You will find three kinds of API styles
    1. Hierarchical style
    2. Varargs container style.
    3. Fluent interface style.

The document model of jRTF is strictly hierarchical. A header just can be add to the document but not to a text. A paragraph can just be part of a document but not part of a header, etc.

If more then one element has to be added to some kind of container varargs are preferred and no Collection classes, which are usually used in Java. E.g.: A section can contain several paragraphs, a paragraph several text parts,a document different headers, etc.

The fluent interface design has been usually chosen when an object can have different states: A paragraph can be aligned and centered, a font definition for the header can be set to bold and has a certain site, and so on.

When it comes to the method names of the fluent interface the prefix "no" and the postfix "on"/"off" are used. "on/off" is only used as a suffix when two different methods can toggle the status. So it’s "noLineNumbering()" and not "lineNumberingOff()" because you can’t toggle the line numbering back.

  1. jRTF builds an internal representation of a RTF document first and writes

it later to a stream. Currently jRTF don’t take advantage of that because it could for example accept a font or color definition during writing a text and insert automatically a header information which is written in the second pass.

What’s not supported and how YOU can help

jRTF is grown out of my own need to generate RTF documents. Some background about this project: http//www.tutego.de/ is a German training institute and we wanted to send a RTF in revision mode to every trainer on a regular basis with his contact details, availability and a table with his seminars. The jRTF template mechanism is used to prepare offers if a customers asks for a training. Later I added things because they were just easy to add: pictures, different formating (but does somebody double underline today?) So for me jRTF does the job and probably I will not add a lot more stuff until I need it.

So a lot of things are missing like nice table handling, bookmarks, comments/annotations, drawing objects, sub documents, all object/shape stuff, embedded fonts, GIF images, and a lot more. The current RTF 1.7 standard has too many control words (around 1400). Some of them are easy to add, some conceptual things are a little bit more work. If you are looking to a mature open source alternative take a look at iText RTF (http://itextrtf.sourceforge.net/).

You can help with

  • testing jRTF
  • finding out where jRTF generates wrong RTF and where exceptions should be thrown
  • adding more control words to jRTF to support more formattings/styles
  • add more field
  • uncomment the style support and make it work
  • make the table stuff work, introduce a RtfCell class
  • add GIF and WMF support
  • Builds an enum for different languages so that the hole document, a certain paragraph or text can be in different languages
  • abstract from font, style and color positions in header and introduce names, which are mapped to these positions

Furthermore some design decisions has to be made according to formattings: The problem now is that some formattings can appear at several places. Take paragraph formattings for example. They can appear in header definitions and also "local" with the paragraph itself. I started using a EnumSet for this formattings which have the big advantage that a format can be reused and building is quite nice. But for consistency with the other classes I changes to the builder style which has the disadvantage of heavy source duplication and the lack of reusing a certain style. This problem can be solved in three different ways:

  1. Continue with the builder style and bring people to using styles so that local paragraph formattings are not necessary.
  2. Offer either a builder style and a EnumSet style.
  3. Change to EnumSet and accept that there a two different API "styles".

Habt ihr auch “Comparison method violates its general contract” (bei Eclipse)?

Für Eclipse 3.6 möchte ich gerade die ersten Plugins installieren (SVN-Client und Google Eclipse Plugin) und bekomme ein “Comparison method violates its general contract”. Der Fehler kommt aus einer neuen Implementierung TimSort fürs Sortieren, http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/src/share/classes/java/util/TimSort.java.html zeigt die Implementierung. Kennt ihr das Problem? Google kennt das Problem nicht wirklich.

SwingX 1.6.1 released

SwingX ist nicht gerade bekannt für eine Open Source Lib, die jeden Monat ein fettes Update raushaut. Doch nun gibt es wieder ein paar Änderungen, die SwingX auf die Version 1.6.1 bringt. Karl listet ein paar Neuerungen auf:

  • Added prompt support.
  • Added new Highlighters and HighlighterPredicates and improved the rendering API.
  • Lots of JXDatePicker and JXMonthView improvements.
  • More Mustang sorting improvements.
  • AutoComplete improvements.

Update 1.6.0_21 (6u21)

Änderungen unter http://java.sun.com/javase/6/webnotes/6u21.html.

Interessantere Dinge:

Support for Customized Loading Progress Indicators

With Java SE 6u21, you can now enhance the loading experience of an application by providing a customized loading progress indicator (sometimes referred to as a progress bar) to better inform the end user of how much of the application has been downloaded during startup. See the following topics for more information:

 

Java VisualVM

Java VisualVM based on VisualVM 1.2.2 is included in Java SE 6u21. This release introduces the following features and enhancements:

  • HeapWalker performance improvements
  • VisualVM-Sampler performance improvements
  • BTrace4VisualVM plugin introduces BTrace 1.1
  • Profiling engine bugfixes
  • Built on NetBeans Platform 6.8

For more information, refer to the VisualVM releases page.

http://java.sun.com/javase/6/webnotes/BugFixes6u21.html

GWT 2.0.4 Release

Der GWT-Blog http://googlewebtoolkit.blogspot.com/2010/06/gwt-204-is-now-available.html kündigt ein kleines Update an, was unter anderem Probleme bei der Umsetzung des Shift-Operators behebt (Fehler in der JS-Engine von Safari):

basically the issue is that a right shift of a value that is internally stored as a double fails to correctly set the integer flag on the internal value at the end of the shift.

Noch zwei weitere Kleinigkeiten wurden angegangen:

Simple OpenOffice templating with the ODF toolkit

To open an OpenOffice text document and access the text you first have to download odfdom-0.8.5-binaries.zip (Homepage of ODF TOOLKIT) and add odfdom.jar to your classpath together with a recent Xerces implementation like xercesImpl-2.9.0.jar. Then you can start with Java:

File file = new File( "C:/Users/Christian/Desktop/TEMPLATE.odt" );
OdfTextDocument odf = (OdfTextDocument) OdfTextDocument.loadDocument( file );
OdfOfficeText contentRoot = odf.getContentRoot();

The OdfOfficeText gives access to the XML-structure of the document. If you print it out

System.out.println( contentRoot );

it looks like this:

<office:text>
    <office:forms form:apply-design-mode="false"
        form:automatic-focus="false"></office:forms>
    <text:variable-decls>

    </text:p>
</office:text>

With regular XML-DOM operations you can now modify the document.

To use a template you have to a) find a certain element you want to fill b) modify it and c) save the document.

a) For templates you can use user variables. If you set a variable it looks like this in XML:

<text:variable-set office:value-type="string" text:name="COURSETITLE">COURSETITLE</text:variable-set>

(Date and other formats look different!)

b) After your found the XML element either by hand or XPath, you can modify an entry with setNodeValue() or different method if the value is stored in attributes.

c) Save the modified document with odf.save( file );

A simple but complete example to read a document, set variables and write the modified ODT:

import java.io.File;
import java.util.*;
import org.odftoolkit.odfdom.doc.OdfTextDocument;
import org.odftoolkit.odfdom.doc.office.OdfOfficeText;
import org.w3c.dom.*;

public class OdtTemplate
{
  private OdfTextDocument odf;
  private Map<String, String> map = new HashMap<String, String>();

  public static void main( String[] args ) throws Exception
  {
    File file1 = new File( "C:/Users/Christian/Desktop/TEMPLATE.odt" );
    File file2 = new File( "C:/Users/Christian/Desktop/result.odt" );

    OdtTemplate template = new OdtTemplate();
    template.readOdt( file1 );
    template.setVariable( "COURSETITLE", "Donuts backen für Kernkraftfahrer" );
    template.setVariable( "COURSECODE", "DONUT" );
    template.setVariable( "CREATOR", "ull" );
    template.saveOdt( file2 );
  }

  public void readOdt( File file ) throws Exception
  {
    odf = (OdfTextDocument) OdfTextDocument.loadDocument( file );
  }

  public void setVariable( String key, String value )
  {
    map.put( key, value );
  }

  public void saveOdt( File file ) throws Exception
  {
    OdfOfficeText contentRoot = odf.getContentRoot();
    iteratorOverEveryVariableSet( contentRoot.getChildNodes() );
    odf.save( file );
  }

  private void iteratorOverEveryVariableSet( NodeList childNodes )
  {
    for ( int i = 0; i < childNodes.getLength(); i++ )
    {
      Node item = childNodes.item( i );

      if ( item instanceof NodeList )
        iteratorOverEveryVariableSet( item.getChildNodes() );

      if ( item.getNodeName().equals( "text:variable-set" ) )
      {
        String nodeValue = item.getAttributes().getNamedItem( "text:name" ).getNodeValue();
        item.getChildNodes().item( 0 ).setNodeValue( map.get( nodeValue ) );
      }
    }
  }
}