Von Google Guava gibt es ein Update von r05 auf r06. Die Updates sind nicht so dramatisch und hier aufgeführt:
Autor: Christian Ullenboom
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.
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.
- 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.
- jRTF is able to run on the Google App Engine because classes like Color, Font, FileWriter and other black-listed classes aren’t used.
- It should not be possible to generate illegal RTF and the library should throw exceptions if strange things happen. (It could do better…)
- You will find three kinds of API styles
- Hierarchical style
- Varargs container style.
- 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.
- 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:
- Continue with the builder style and bring people to using styles so that local paragraph formattings are not necessary.
- Offer either a builder style and a EnumSet style.
- 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:
- Customizing the Rich Internet Application Loading Experience
- Customizing the Loading Experience topic in the Java Tutorials
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.
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):
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 ) );
}
}
}
}
Erste Realisierung von ARM-Blöcken
Links zu Automatic Resource Management (ARM)
- http://mail.openjdk.java.net/pipermail/coin-dev/2009-February/000011.html
- http://blogs.sun.com/darcy/entry/project_coin_arm_api
Auch das Format von Stack-Traces kann sich durch suppressed exceptions ändern. Später dazu im Buch mehr.
Eclipse 3.6 (Helios) verfügbar
Nach NetBeans 6.9 ist nun auch die Version Eclipse 3.6 final:
- http://www.eclipse.org/downloads/
- New features for Java developers
- New APIs in the Platform and Equinox
- New features for plug-in developers
- New features in the Platform and Equinox
In der JDT bleiben die Änderungen bescheiden.
JDK 7 Milestone 8 (build 96) verfügbar
Damit ist Java 7 nun offiziell Feature Complete. Ankündigungen unter http://blogs.sun.com/openjdk/entry/openjdk_roundup. Noch 2 Meilen bis zum finalen Release. http://openjdk.java.net/projects/jdk7/features/ führt JSR 296: Swing application framework und auch Swing JDatePicker component als “dropped” auf.
Gedärme: Event Bus für Google Guice
Zwei Konzepte sind für mich zentral: Dependency Injection und Events. Nach dem jetzt DI durch CDI standardisiert ist, steht das für einen Event Bus noch aus. (CDI-kann man aber so interpretieren.) Über eine Lösung habe ich schon geschrieben: http://www.tutego.de/blog/javainsel/2009/03/einfuhrung-in-den-eventbus/. Ein Event Bus sollte natürlich mit einem DI-Container harmonieren. Nutzer von Google Guice können das mit Guts (englisch für Gedärme aber auch Mut) tun: http://kenai.com/projects/guts/pages/Home. Die Doku http://guts.kenai.com/guts-events/apidocs/ zeigt wie es geht:
1. Modul aufbauen
Injector injector = Guice.createInjector(new EventModule(), new AbstractModule() { @Override protected void configure() { Events.bindChannel(binder(), Integer.class); } });
Wie man sieht, wird ein Ereignistyp (hier Integer) registriert. Der Kanal kann auch einen Namen tragen:
Events.bindChannel(binder(), Integer.class, "TOPIC1");
2. Der Kanal wird nun injziert und man kann Ereignisse versenden:
public class Supplier { @Inject Supplier(Channel<Integer> channel) { // Send an event to this channel (i.e. to all its consumers) channel.publish(10); ... } ... }
3. Zum Empfang:
public class MyClass { @Consumes public void push(Integer event) { ... } ... }
SmartGWT 2.2 ist raus
- Selenium Support
- Support for the prototype pattern to set global defaults without creating a separate hierarchy of subclasses. This is explained in more detail in the release announcement
- DateRangeItem, MiniDateRangeItem and Relative Date support for DynamicForm
- Dropdown multi-selects
- Javadoc enhancements : Over 200 API’s have an overview and relevant Showcase sample in the @see link of the API docs
- Numerous other fixes and enhancements.
- Several new Showcase samples
Der Showcase zeigts: http://www.smartclient.com/smartgwt/showcase/. 270 Beispiele sind schon eine stolze Zahl.
Aktuelles JDK 1.7-Build für Mac verfügbar
private final ist doof bei JAXB
Eclipse kann beim Speichern Aktionen ausführen. So
- räumt es automatisch die import-Anweisungen auf,
- entfernt Weißraum am Ende einer Zeile,
- setzt @Overide an überschriebenen Methoden
- …
Zum Testen habe ich heute morgen eine Einstellung gesetzt, die mir Attribute, die final gemacht werden können, auch final macht. Fand ich nett.
Doch dann kam der Abend. Plötzlich initialisierte meine App keine JAXB Beans mehr ein. Es kostete mich 10 Minuten herauszufinden, dass diese blöde Einstellung das Problem verursacht. Denn wenn statt
@XmlRootElement( name = "course" ) @XmlAccessorType( XmlAccessType.FIELD ) public class Course { private String htmlkeywords = ""; private String htmlhead = "";
steht
… public class Course { private final String htmlkeywords = ""; private final String htmlhead = "";
dann wird JAXB die finalen Variablen natürlich nicht mehr initialisieren können. Meine Beans werden nur gelesen, sodass kein Setter die Variablen verändert – die Beans sind immutable. Die Eclipse Save Einstellung das final magisch dranzusetzen passt dazu nicht.
Tomcat 7 RC 2
Die Tomcat Entwicklung ist nicht die schnellste, aber immerhin ist jetzt der 2 RC unter http://people.apache.org/~markt/dev/tomcat-7/v7.0.0-RC2/ verfügbar. Es gab zuletzt mit der neuen Asnyc-Fähigkeit aus der Servlet 3.0 Spezifikation noch einige Probleme doch sonst sollte alles so laufen wie bisher. Eclipse 3.6 WTP wird auch fit gemacht für Java EE 6 und Servlet 3.0 — wollen wir hoffen, dass das ein produktives Pärchen wird.
Thema der Woche: java.util.Collections, java.util.Arrays
- Was ist die Aufgabe der Klasse java.util.Collections und Arrays?
- Gruppiere die Methoden der beiden Klassen.
- Was ist die Funktion einer Gruppe und warum gibt es die Methoden? Finde zu jeder Methoden einer Gruppe ein Beispiel mit Hilfe einer Quellcodesuchmaschine (http://dev.koders.com/ oder http://www.google.com/codesearch) und nenne den Motivation hinter der Nutzung.
- Welche Methoden sind in Java 5, Java 6 und Java 7 hinzugekommen. Kann man Gründe für den Zuwachs anführen?
- Hat Google Collections hat eine weitere Utility-Klasse für Datenstrukturen? Wenn ja, was bietet sie? Wenn nicht, warum ist sie nicht nötig?
Einfaches Testen von Servlets mit string-test
Servlets zu schreiben gehört nun nicht gerade zu meinem Alltagsaufgaben, aber für ein JSON-Endpoint muss ein Servlet nun doch mit ins Boot. (REST-API geht leider nicht.) Einen Test dafür zu schreiben finde ich selbstverständlich, da ich geil auf grüne Balken bin (nein, nicht die Download-Balken). Es kommen für Servlet-Tests unterschiedliche Ansätze in Betracht, die sich grundsätzlich in 2 Gruppen einteilen lassen:
- Tests mit einem echten (embedded) Servlet-Container
- Mock-Tests
Dass ich ein Jetty-Fan bin ist vielleicht schon in früheren Posts rübergekommen, aber hier lasse ich meinen Lieblingsserver links liegen und gehe auf die Mock-Tests. Gut funktioniert für mich spring-test. Ein Beispiel.
Das Servlet:
package com.tutego.traida.server.service.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Raplet extends HttpServlet
{
private static final long serialVersionUID = 6942655630840028053L;
@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException,
IOException
{
resp.getWriter().print( "hello " + req.getParameter( "name" ) );
}
}
Der Test:
package com.tutego.traida.server.service.servlet;
import javax.servlet.ServletException;
import org.junit.*;
import static org.junit.Assert.*;
import org.springframework.mock.web.*;
public class RapletTest
{
private Raplet servlet = new Raplet();
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@Before
public void before() throws ServletException
{
servlet.init( new MockServletConfig() );
this.servlet = new Raplet();
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
}
@Test
public void doGetTest() throws Exception
{
request.setParameter( "name", "tutego" );
servlet.doGet( request, response );
assertEquals( "hello tutego", response.getContentAsString() );
}
}
Einfacher geht’s nun wirklich nicht mehr.
Zum Ablaufen des Tests packe in den Klassenpfad:
- http://grepcode.com/snapshot/repo1.maven.org/maven2/org.springframework/spring-test/3.0.2.RELEASE
- http://grepcode.com/snapshot/repo1.maven.org/maven2/org.springframework/spring-core/3.0.2.RELEASE
Zwar bin ich kein Spring Fan Boy, aber mit 2 Archivdateien brennt die Jar-Hölle nicht so heiß (die Abhängigkeiten sind übertrieben).
com.google.appengine.api.datastore.* Typen für GWT serialisieren
Wer Datentypen wie com.google.appengine.api.datastore.Text in seiner Bean nutzt kann die Datentypen serialisieren. Wenn man nun eine Bean mit zum Beispiel dem Typ Text nach GWT serialisiert, der wird bemerken, dass GWT diese Datastore-Datentypen nicht unterstützt. Nun reicht es nicht, eine Kopie von etwa der Klasse Text anzufertigen und in den Quellordner zu setzen, da die Klasse nicht im client-Paket ist. Stattdessen ist ein etwas anderes Vorgehen nötig. Denn um Java-Klassen auch außerhalb vom client-Paket platzieren zu können, ist in der XML-Datei in Eintrag wie der folgende nötig;
<super-source path=""/>
Um das für die Datastore Klassen nicht selbst schreiben zu müssen, können wir auf die Implementierung unter http://www.resmarksystems.com/code/ zurückgreifen. Wir
- setzen <inherits name="com.resmarksystems.AppEngineDataTypes"/> in unsere GWT-XML-Datei und
- laden http://www.resmarksystems.com/code/appengine-utils-client-1.0.jar und setzten das Jar in unsern lib-Ordner
Das war’s schon. Serverseitig muss nichts gemacht werden.
Erster Milestone von GWT 2.1
Und es gibt tolle Neuigkeiten. Zum einen Data Presentation Widgets (Widgets zur effizienten Darstellung großer Datenmelgen) zusammen mit einem MVP-Framework.
Aus dem GWT-Blog:
With GWT 2.1 Milestone 1, you are one step closer to being able to build business apps for the cloud as easily as ever. Using GWT’s new data presentation widgets and MVP framework, you can create great looking web apps that run fast, whether you’re interacting with 25 records or 25 million records. This is accomplished by designing the widgets to be extremely lightweight, using DIVs and HTML instead of composites and widgets, and an app framework that makes it easy to fetch only the data you need, when you need it.
To make building web apps even faster, you can now use VMware’s Spring Roo to create a functional app with a few commands. All of these tools are available, including the Google Plugin for Eclipse and App Engine SDK, within SpringSource Tool Suite (STS) — providing you an integrated development environment.
And since it’s written using GWT, your resulting app is an HTML5 app that is cloud ready from the beginning.
Hier zu den Release-Notes.
Thema der Woche: Gekonnt mappen mit Annotationen
- Was haben http://jsefa.sourceforge.net/ und https://args4j.dev.java.net/ gemeinsam?
- Schreibe ein Programm, welches von der Kommandozeile eine CSV-Datei erwartet. Hilfe bei fehlender Dateiangabe soll gegeben werden.
- Die CSV-Datei soll eingelesen und als Tabelle in ein HTML-Dokument konvertiert werden. Kommandozeilenargumente bestimmen, ob die Ausgabe auf die Konsole geht oder in eine Datei. Nutze dafür args4j und jsefa.
- Es gibt gewissen Standards für Kommandozeilenoptionen. Welche sind das und was sind Quellen.