Schönes Beispiel für Generics
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Freitag, Juli 03, 2009.
Thema der Woche: Effective Java
3 Kommentar(e). Veröffentlicht von Christian Ullenboom am Freitag, Juli 03, 2009.Gehe die verfügbaren Informationen durch:
- Online-Version der ersten Auflage
- Aus der 2. Aufgabe ist das Generics-Kapitel frei verfügbar: http://java.sun.com/docs/books/effective/generics.pdf
- developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf
- http://sites.google.com/site/io/effective-java-reloaded
- http://jaoo.com.au/brisbane-2009/file?path=/jaoo-sydney-2009/slides/JoshuaBloch_KeynoteEffectiveJavaStillEffectiveAfterAllTheseYears.pdf
Labels: Die wöchentliche Dosis Java
Welches Projekt wird von Maven wie oft referenziert?
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juli 02, 2009.- das HSQLDB doch noch so oft (für Tests) gebraucht wird, aber Derby noch auf die erste Seite kommt,
- Spring (schon) so weit oben seht,
- CXF vor Axis und dem alten XFire steht,
- JAXB so groß im Einsatz ist,
- Plexus von CodeHaus in der Liste auf der ersten Seite steht (unter anderem von Maven2 genutztes IoC-Framwork und daher wohl so weit vorne),
- dom4j populärer als JDOM ist,
- Struts ist (ein wenig) wichtiger als WebWork aber weit abgeschlagen von JSF.
- http://classworlds.codehaus.org/
- http://qdox.codehaus.org/
- http://www.janino.net/
Labels: Open Source
JavaDoc in Wiki-Notation statt HTML
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juli 02, 2009.Das ist das Ziel vom http://code.google.com/p/markdown-doclet/. Mit der Syntax von http://daringfireball.net/projects/markdown/syntax und zusammen mit leicht optimiertem CSS und kleinen UML-Diagrammen für die Hierarchien, folgt:
Labels: Open Source
IDE-Woche: Eclipse 3.5, NetBeans 6.7, IntelliJ 9 M1
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juli 02, 2009.So viel IDE gab es noch nie. In einer Woche drei wichtige Neuerungen.
- Mit viel Tamtam wurde Eclipse 3.5 (Galileo) veröffentlicht. http://www.eclipse.org/downloads/
- Bei Sun gibt es mit NetBeans 6.7 ebenfalls ein neues Release. http://www.netbeans.org/servlets/NewsItemView?newsItemID=1399
- IntelliJ IDEA 9 Milestone 1 ist verfügbar. http://www.jetbrains.com/idea/nextversion/index.html?utm_source=TSS&utm_media=Anouncement&utm_campaign=IDEA9_M1. IntelliJ ist Vorreiter bei Java EE 6 und integriert auch Google Android Entwicklung und weitere Innovationen.
Labels: Entwicklungsumgebung
JaQue Version 1.5: MS LINQ Expression Trees für Java
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juni 11, 2009.Von der Webseite:
JaQue provides an infrastructure for Microsoft LINQ like capabilities on Java platform. Using ASM, JaQue builds expression trees, which are used to build a query in domain specific technology or language, such as SQL. This way Java developers can focus on writing application logic in the language they know - Java, regardless what the underlying technology or language is in use. JaQue to Objects and JaQue to XML are currently supported and JaQue to JPA is under development.
Ein Beispiel macht das praktisch deutlich:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernate");
EntityManager em = emf.createEntityManager();
JaqueEntityManager jem = new JaqueEntityManager(em);
Queryable<Order> orders = jem.from(Order.class);
System.out.println(count(where(new Predicate<Order>() {
public Boolean invoke(Order t) throws Throwable {
return t.getOrderID() > 11000;
}
}, orders)));Wie bei LINQ soll eine eine API für die verschiedenen Datenquellen geben, also XML, Objekte, Datenbanken, … Für JPA schreibt die Seite “Currently it's able to perform only simple SELECTs, JOINs and AGGREGATEs”. Das ist natürlich nicht viel. Insofern ist diese Lösung WEIT von den LINQ to SQL-Möglichkeiten entfernt.
Der Hinweis der Webseite auf “Interoperability with Java Closures” ist natürlich hinfällig. Dadurch, dass Closures aber wegfallen, wird die ganze API viel aufgeblähter, als wenn man Closures hätte. Die Scala-Variante ist daher auch viel kürzer.
PS: Die nächsten 2 Wochen gibt es keine Blog-Einträge, da ich ich Afrika bin.
Labels: Open Source
GWT-bezogene Videos von der Google I/O Konferenz 2009
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Mittwoch, Juni 10, 2009.Im Google Code Blog werden einige Videos vorgestellt, die den aktuellen Zustand von GWT widerspiegeln. Etwa
GWT Can Do What?!?! A Preview of Google Web Toolkit 2.0 (PDF):
Und weitere:
Google Web Toolkit Architecture: Best Practices for Architecting your GWT App
Measure in Milliseconds: Performance Tips for Google Web Toolkit
Effective GWT: Developing a Complex, High- performance App with Google Web Toolkit
The Story of your Compile: Reading the Tea Leaves of the GWT Compiler for an Optimized Future
Progressively Enhance AJAX Applications with Google Web Toolkit and GQuery
Building Applications with Google APIs
Labels: GWT, Web Frameworks
Mit AjaxSwing Swing Anwendungen als Web-Anwendungen laufen lassen
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Montag, Juni 08, 2009.Labels: Swing, Web Frameworks
Thema der Woche: Pull-Parser/StAX
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Montag, Juni 08, 2009.Nicht immer können und müssen Objektgraphen von XML-Dateien – entweder pur als XML-DOM, oder gemappt über etwa JAXB – im Speicher gehalten werden. Muss nur einmal eine XML-Datei abgelaufen werden (natürlich können in diesem einen Durchlauf dann der XML-DOM aufgebaut werden), kann gut ein Pull-Parser eingesetzt werden.
- Lies Serielle Verarbeitung mit StAX
- Warum kann ein Pull-Parser schnell als Push-Parser (SAX) arbeiten?
- Verstehe im Groben http://jira.codehaus.org/secure/attachment/28197/StaxBuilder.java.
- Implementiere einen XHTML-Prüfer, der meldet, ob im img-Tag das Attribut alt gesetzt ist.
Labels: Die wöchentliche Dosis Java
Ext GWT Beispiel mit EditorGrid/GroupingView/GroupingStore
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Samstag, Juni 06, 2009.GroupingStore<BaseModel> store = new GroupingStore<BaseModel>();
BaseModel c1 = new BaseModel();
c1.set( "title", "Java 1" );
c1.set( "category", "JAVA" );
c1.set( "price", 100 );
store.add( c1 );
BaseModel c2 = new BaseModel();
c2.set( "title", "Java 2" );
c2.set( "category", "JAVA" );
c2.set( "price", 200 );
store.add( c2 );
BaseModel c3 = new BaseModel();
c3.set( "title", "C#" );
c3.set( "category", ".NET" );
c3.set( "price", 100 );
store.add( c3 );
List<ColumnConfig> config = new ArrayList<ColumnConfig>();
config.add( new ColumnConfig( "category", "Kategorie", 200 ) );
config.add( new ColumnConfig( "title", "Titel", 100 ) );
config.add( new ColumnConfig( "price", "Preis", 100 ) );
store.groupBy( "category" );
final ColumnModel cm = new ColumnModel( config );
GroupingView view = new GroupingView();
view.setShowGroupedColumn( false );
view.setForceFit( true );
view.setGroupRenderer( new GridGroupRenderer()
{
public String render( GroupColumnData data )
{
String header = cm.getColumnById( data.field ).getHeader();
String items = data.models.size() == 1 ? "Eintrag" : "Einträge";
return header + " " + data.group + " (" + data.models.size() + " " + items + ")";
}
} );
EditorGrid<BaseModel> grid = new EditorGrid<BaseModel>( store, cm );
grid.setView( view );
grid.setBorders( true );
grid.setAutoHeight( true );
ContentPanel cp = new ContentPanel();
cp.add( grid );
cp.setHeight( 500 );
RootPanel.get().add( cp );
Labels: GWT, Web Frameworks
Will ich eigentlich RIA mit Ext GWT?
4 Kommentar(e). Veröffentlicht von Christian Ullenboom am Samstag, Juni 06, 2009.Nach dem ich nun eine Woche eine Anwendung mit Ext GWT (GXT) zusammengebaut habe, kommen mir Zweifel, ob Ext GWT überhaupt das richtige für meinen Anwendungsfall ist. Einige Fragen in dem Zusammenhang:
Ist Ext GWT 2.0 M2 gut gewählt?
Ext GWT 2 gibt es noch gar nicht lange (http://extjs.com/blog/2009/05/20/ext-gwt-20-milestone-2-released/), neues M2 Release also vor 2 Wochen, und die Komponenten sind grundsätzlich toll. Auf der Demo Seite http://extjs.com/examples-dev/explorer.html#overview kann man sich das anschauen.
Probleme: Ext GWT 2.0 hat in meinen Augen sehr vielen Änderungen in der API. Quellcode für Ext GWT 1.0 findet man im Netz, doch viele Beispiele lassen sich nicht ohne weiteres auf die 2er Version übertragen. Wer migrieren will/muss wird noch seinen Spaß bekommen. Einige Beispiele laufen in der Demo nicht (http://extjs.com/examples-dev/explorer.html#grouping), bei anderen fehlt der Quellcode im Demo. Da muss man dann die Quellen laden.
Laut Ankündigung müsste GXT schon längst fertig sein.
Was passt mir an Ext GWT nicht?
- Die Dokumentation. Einfache Beispiele zu finden kostet viel Zeit. Es fehlt so etwas wie ein Java-Almanac für Ext GWT. Aus komplexen Szenarien kann man sich einfache Beispiele ableiten, von dort diese auf seinen Anwendungsfall übertragen. Selbst die Beispiele aus dem ShowCase könnten einfacher sein, denn der ShowCase nutzt interne “Demo-Datengeber-Klassen”. Hier wären in meinen Augen einfachere Beispiele gut gewesen, die wirklich eigenständig sind um schnell die wichtigsten Schnittstellen ablesen zu können.
- Compiliere ich meine Programme, so lassen sich im Browser plötzlich keine Textfelder mehr selektieren und den Cursor sieht man nicht.
- Das Layout-Handing. Da die Ext GWT Anwendungen auf eine “Bildschirmseite” kommen, und weniger auf einem beliebig langen HTML-Dokument, gibt es Probleme mit den Höhen. Manches mal sind die Elemente in einem Scroll-Container zu klein, dann zu groß. Ich habe viel Zeit damit verbracht, große Tabellen in den richtigen Größen auf den Container zu setzen.
- Während das Orginal-GWT viele eher den typischen Web-Charakter hat, basiert Ext GWT auf dem Applikationsgedanken: (Popup-)Menüs in Web-Applikationen? Hm …
- Anpassungen des Aussehens sind eine Qual. Die CSS-Datei gxt-all.css ist 6478 Zeilen lang, gxt-gray.css noch mal 443! Wer viel Zeit hat, kann einmal versuchen, den Font 2 Pixel größer zu setzen. Dazu müssen natürlich auch die Icons passen. Strg++ geht nicht einfach so.
- Es “erfindet” GXT eigentlich alles neu: Widgets, Container, Layout-Manager, Grafik-Einbindung, …. Besonders blöd ist das bei den Grafiken, wo Google mit Proxies einen schönen Ansatz fährt.
- Es gibt keinen Gui-Builder, für GWT aber schon.
War Ext GWT eine gute Wahl, oder hätte es doch SmartGWT sein sollen?
Das weiß ich nicht, denn mit SmartGWT habe ich nur einfache Beispiele programmiert. Ext GWT hat aber den gleichen RIA-Ansatz wie SmartGWT, und unterscheidet sich nicht großartig im Ansatz. Die GXT-Komponenten sehen auf jeden Fall super aus. Daher hat mich GXT ja auch so angezogen. Wer hübscher ist gewinnt :) Die Komponenten sind fancy und meine Lieblinge sind http://extjs.com/examples-dev/explorer.html#advancedcharts (cool), http://extjs.com/examples-dev/explorer.html#gridplugins, http://extjs.com/examples-dev/explorer.html#grouping, http://extjs.com/examples-dev/explorer.html#filtertree, http://extjs.com/examples-dev/explorer.html#gridtogrid.
Ist ein RIA-Framework wie GXT immer gut?
Das ist eigentlich die zentrale Frage.
- Die Standard-Komponenten von GWT sind etwas “einfach”. Natürlich nutzt GXT das GWT als Infrastruktur, aber hat sich in meinen Augen weit davon entfernt.
- GXT versucht, alle Desktop-Komponenten in den Browser zu bekommen. Und so bekommen wir immer mehr und mehr tolle Komponenten. Das hat aber seinen Preis! Der generierte JavaScript-Code wird schnell astronomisch. Und die Anwendungen sehen eben nicht mehr so aus wie Webseiten. Das ist mal gewollt, mal nicht gewollt. Ein richtig und falsch gibt es nicht! Wer aber vollständige Applikationen im Web-Schreiben möchte, der bekommt mit GXT ein gutes Framework. Alles ist vorbereitet und das Look-and-Feel konsistent.
- Änderungen des Aussehens sind aufwändig. Wenn man also HTML/CSS sehen und damit designen möchte, ist mit GXT nicht optimal bedient. (Als nächstes teste ich http://code.google.com/p/google-web-toolkit-incubator/wiki/UiBinder --- wenn der denn mal im Trunk ist…) Soll ein (echte) Webdesigner eine GXT-Anwendung skinnen, wird der sicherlich nicht glücklich werden. Es ist eben nicht Design first.
Labels: GWT, Web Frameworks
Ich habe ja schon nicht mehr damit gerechnet: SwingX hat es in den 1.0 Status geschafft. Die Fixes/Enhancements sind aber eigentlich minimal und die Freigabe hätte schon früher kommen können …
- Download: http://swinglabs.org/downloads.jsp
- SwingX-Forum: http://forums.java.net/jive/forum.jspa?forumID=73
Und wenn man liest, “From now on, the Java 5 compatibility will no longer be maintained.” heißt das nur, dass die kommenden Versionen mindestens Java 6 erwarten; SwingX 1.0 ist selbstverständlich unter Java 5 lauffähig.
Labels: Swing
Einen einfachen Baum mit Ext GWT (Tree, TreeItem)
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juni 04, 2009.Im Mittelpunkt steht com.extjs.gxt.ui.client.widget.tree.Tree, dem entweder com.extjs.gxt.ui.client.widget.tree.TreeItem-Objekte zugeordnet werden, oder ein komplexeres Modell zugewiesen wird. Mit TreeItem ist schnell ein statischer Baum aufgebaut:
Tree tree = new Tree();
TreeItem rootTreeItem = new TreeItem( "Hauptobjekte" );
tree.getRootItem().add( rootTreeItem );
rootTreeItem.add( new TreeItem( "Kunden" ) );
rootTreeItem.add( new TreeItem( "Seminare" ) );
rootTreeItem.add( new TreeItem( "Referenten" ) );
rootTreeItem.setExpanded( true );
tree.addListener( Events.OnClick, new Listener<TreeEvent>()
{
@Override public void handleEvent( TreeEvent be )
{
if ( be.getItem().isLeaf() )
Info.display( "Element: ", be.getItem().getText() );
}
} );
contentPanel.add( tree );
Wie bei Swing gibt es ein Root-Icon und darunter liegen die Kinder.
Mit einem Listener lässt sich erfragen, ob der Baum ausgefaltet wird oder ob Blätter ausgewählt wurden. Das Beispiel hört nur auf die Auswahl der Kinder und gibt eine Meldung aus.
Labels: GWT
Quaqua Look And Feel. Das bessere Mac OS X LaF
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Juni 04, 2009.Quaqua ist ein Swing-LaF, was besonders gut an die Apple Human Interface Guidelines ranreicht.
Das Demo läuft auch unter Windows.
Features (von der Webseite):
- (Nearly) Native User Experience
Quaqua user interface delegates closely look and behave like their native counterparts. Complex user interface components, such as JFileChooser and JColorChooser, are close enough to make end users feel comfortable with them. - Blends into OS X Designs
Quaqua supports three OS X designs: Tiger, Panther, Jaguar. Quaqua automatically chooses the right design for the current operating system. - Alternative Styles
Quaqua offers alternative styles for many user interface elements. Such as small styles for most of the components, as well as a striped style for tables, lists and trees. Jaguar-design like tabbed panes with stacking tabs are also supported. - Additional Components
Quaqua provides Swing implementations of NSBrowser and NSSheet (named JBrowser and JSheet). - Clean Layout
Laying out Aqua components with Java is quite challenging. Quaqua provides an API for component alignment based on visual criteria (baseline, visual bounds, preferred gaps). JScrollPane's automatically avoid overlaps with the grow-boxes of windows. - Localized in four languages
Quaqua is localized in the following languages: German, French, Italian and English.
Neben dem LaF für Standardkomponenten gibt es mit JBrowser und JSheet noch zwei “Spezialkomponenten”.
Die Lizenz ist License (LGPL or BSD), und die Doku mit vielen Screenshots. Tolle Arbeit!
Labels: Open Source, Swing
Die Duke-Awards 2009 ...
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Mittwoch, Juni 03, 2009.Wie viel GWT steckt in Google Square?
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Mittwoch, Juni 03, 2009.vom GWT nahe legt:
<link rel="stylesheet" href="/squared/styles/squared.css">
<script language="javascript" src="/squared/js/templates.js"></script>
<script language="javascript" src="/squared/api/com.google.quality.views.squared.client.Squared.nocache.js"></script>
Verfolgt man den Link ist das typische obfuscated JavaScript zu sehen. Wer viiiiel Zeit hat, kann das ja mal debuggen und hier berichten. Ein kleiner Test mit FireBug zeigt, dass Squared sich über Service per RPC die Objekte geben lässt
["com.google.quality.views.squared.shared.model.Workspace/4054808271","US presidents",
"com.google.quality.views.squared.shared.model.Suggestions/3280816700",
"java.util.ArrayList/3821976829",
"com.google.quality.views.squared.shared.model.Entry/3459296909" ...
Labels: GWT, Web Frameworks
Labels: Open Source
OpenOffice Draw + XForms Export + iText = PDF
3 Kommentar(e). Veröffentlicht von Christian Ullenboom am Montag, Juni 01, 2009.Für unseren Seminarbetrieb erstellen wir nach dem Seminarabschluss aus einer XML-Datei die Rechnung und Zertifikate für den Kunden. Die Vorlagen sind in OpenOffice verfasst und können ohne Probleme verändert werden. Ein großer Vorteil ist weiterhin, dass OO einen PDF Exporter mitbringt.
Der Nachteil der Lösung, OpenOffice für die PDF-Erzeugung fernzusteuern ist, dass es sehr schwergewichtig. OO muss installiert und gestartet werden. Das ist auf einem Server, etwa einem einfachen Servlet-Container oder sogar der Google App Engine for Java natürlich nicht denkbar.
Ein anderer Weg ist daher, zwar weiterhin OpenOffice für die Erstellung einer Vorlage zu verwenden, aber beim PDF-Export anders vorzugehen. Die Lösungen können Acrobat Forms (Acroforms) bieten, also eigentlich interaktive Felder, die man später über ein Programm füllen kann. Im ersten Schritt erzeugt man daher mit OpenOffice Draw eine Formular. (Das wird etwa beschrieben unter http://www.devx.com/opensource/Article/38178/.) Dann exportiert man das Dokument in PDF unter Erhaltung der Formulareigenschaften. Dieses PDF lässt sich nun mit iText auslesen, die Formularzellen füllen und wieder als PDF schreiben. Dabei kann die “Formulareigenschaft” wegfallen, dass man später bei dem PDF-Dokument nichts mehr von interaktiven Elementen sieht.
import java.io.FileOutputStream;
import com.lowagie.text.pdf.*;
public class FillInPdfForm
{
public static void main(String[] args) throws Exception
{
PdfReader reader = new PdfReader("c:/rein.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("c:/raus.pdf"));
BaseFont font = BaseFont.createFont("c:\\windows\\fonts\\Calibri.ttf", BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
AcroFields form = stamper.getAcroFields();
for( Object o : reader.getAcroForm().getFields() )
form.setFieldProperty( ((PRAcroForm.FieldInformation) o).getName(), "textfont", font, null);
form.setField("name", "Christian Ullenboom");
form.setField("content", "Brav sein\nLieb sein");
stamper.setFormFlattening(true);
stamper.close();
}
}
Etwas lästig ist, dass beim Ausfüllen der in OO zugewiesen Font flöten geht. Daher muss man diesen neu zuweisen. Sonst ist es Arial/Helvetica.
Labels: Open Source
Wie Google Wave das GWT antreibt
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Sonntag, Mai 31, 2009.
Wirklich interessant ist ist die Tatsache, dass die Clientseite von Google Wave in GWT implementiert ist. Das ist in meinen Augen ein unschlagbares Argument für die Ausgereiftheit von GWT, wenn Google das in einem Projekt einsetzt, was von unglaublichen vielen Menschen verwendert werden wird und definitiv performant laufen muss. Dabei sollte laut einem Blog-Eintrag http://mtwong.ning.com/profiles/blogs/google-io-conference-google-1 Wave auch überhaupt nicht in GWT entwickelt werden, da der Projektleiter Zweifel hatte, GWT würde gescheit laufen. Aber Wave hat wohl auch die Entwicklung von GWT positiv beeinflusst, etwa bei den Tools. Der Blog-Eintrag erwähnt interessante weitere Projekte und GWT-Features:
Labels: GWT
Update JDK 1.6.0_14 (6u14)
3 Kommentar(e). Veröffentlicht von Christian Ullenboom am Freitag, Mai 29, 2009.Änderungen listet http://java.sun.com/javase/6/webnotes/6u14.html auf. Interessant sind meines Erachtens: Compressed Object Pointers und Garbage First (G1) Garbage Collector, weil diese Dinge sind, die für Java 7 vorgesehen waren. Aber nun kann man die schon mal “in the wild” testen, was eine gute Sache ist. Dann noch JAX WS 2.1.6 and JAXB 2.1.10 und ein Update von JavaDB (wobei Derby schon deutlich weiter ist, komisch).
Labels: Java SE
Vorschläge für Projekt Coin (Java 7 Sprachänderungen) geht in die nächste Runde
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Freitag, Mai 29, 2009.Strings in switch,
Joe DarcyImproved Exception Handling for Java,
Neal GafterAutomatic Resource Management,
Josh BlochImproved Type Inference for Generic Instance Creation,
Jeremy MansonElvis and Other Null-Safe Operators, Neal Gafter, Stephen Colebourne
Simplified Varargs Method Invocation,
Bob Lee
Integer-Literale:
Byte and Short Integer Literal Suffixes,
Bruce ChapmanBinary Literals,
Derek FosterUnderscores in numbers,
Derek Foster
Language support for JSR 292
(wiki),
John RoseIndexing access syntax for Lists and Maps,
Shams Mahmood ImamCollection Literals,
Joshua BlochLarge arrays (revised),
James Lowden
Labels: Java 7
Initialisierung von Schnittstellenkonstanten
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Mai 28, 2009.Eine Schnittstelle kann Attribute deklarieren, aber das sind dann immer initialisierte public final static Konstanten.
import java.util.Properties;
public interface PropertyReader
{
Properties DEFAULT_PROPERTIES = new Properties();
Properties getProperties();
}
Würden wir DEFAULT_PROPERTIES nicht mit new Properties() initialisieren, gäbe es einen Compilerfehler.
Nun stellt sich das Problem, wenn die statischen Attribute nicht einfach mit einem Objekt initialisiert werden können, sondern wenn zusätzlicher Programmcode zur Initialisierung gewünscht ist. Für unser Beispiel soll das Properties-Objekt unter dem Schlüssel date die Zeit speichern, an der die Klasse initialisiert wurde. Über statische Initialisierer ist dies jedenfalls nicht möglich.
import java.util.*;
public interface PropertyReader
{
Properties DEFAULT_PROPERTIES = new Properties();
static
^
// Hier gibt's den Compilerfehler
// "Interfaces can't have static initializers."
{
DEFAULT_PROPERTIES.setProperty( "date", new Date().toString() );
}
Properties getProperties();
}
Zwar sind statische Initialisierungsblöcke nicht möglich, aber mit zwei Tricks kann die Initialisierung erreicht werden. Eine innere anonyme Kasse ist eine Lösung:
import java.util.*;
public interface PropertyReader
{
Properties DEFAULT_PROPERTIES = new Properties() { {
setProperty( "date", new Date().toString() );
} };
Properties getProperties();
}
Diese Lösung funktioniert allerdings nur, wenn keinen primitiven Werte über extra Programmcode initialisiert werden, und wenn es nicht-finale Klassen sind, von den überhaupt Unterklassen erlaubt sind.
Mit einem anderen Trick lassen sich auch diese Hürden nehmen. Die Idee liegt in der Einführung einer inneren statischen Klasse, die wir $$ nennen wollen. Innerhalb dieser Klasse platzieren einen static-Block. Anschließend muss nur noch eine Dummy-Variable gesetzt werden, damit der Initialisierungsblock der inneren Klasse auch ausgeführt wird, wenn die Klasse geladen wird. Dazu definieren wir die Variable $. Sie ist static und final, also somit eine echte Konstante. Da leider innere Klassen und Konstanten von Schnittstellen nicht privat sein können, und so unglücklicherweise von außen zugänglich sind, geben wir ihnen die schönen kryptischen Namen $ und $$, sodass sie nicht so attraktiv erscheinen.
import java.util.*;
public interface PropertyReader
{
Properties DEFAULT_PROPERTIES = new Properties();
PropertyReaderInit $ = new $$();
static final class $$
{
static
{
DEFAULT_PROPERTIES.setProperty( "date", new Date().toString() );
}
}
Properties getProperties();
}
Innerhalb von static-Block lässt sich auf das Properties-Objekt zugreifen und somit auch die Werte eintragen. Ohne die Erzeugung des Objekts $ geht es nicht, denn andernfalls würde die Klasse $$ nicht initialisiert werden. Das Programm kann nun alle Elemente wie folgt nutzen:
import java.util.Properties;
public class SystemPropertyReaderDemo implements PropertyReader
{
@Override public Properties getProperties()
{
return System.getProperties();
}
public static void main( String[] args )
{
System.out.println( PropertyReader.DEFAULT_PROPERTIES ); // {date=Thu …
}
}
Hinweis: Aufzählugen über enum können einfacher initialisiert werden.
Labels: Insel
MouseInfo und PointerInfo für eine globale Farbpipette
3 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Mai 28, 2009.Mit der Klasse Robot lassen sich zwar Tastatur- und Maus-Ereignisse produzieren und Screenshots nehmen, doch Informationen über die aktuelle Mausposition liefert die Klasse nicht. Auch das MouseEvent liefert nur die aktuellen relativen Koordinaten bei einem Fenster, doch nicht die Position der Maus auf dem physikalischen Schirm.
Die Klasse MouseInfo liefert diese Information. Die statische Funktion MouseInfo.getPointerInfo() liefert ein PointerInfo-Objekt, das Aussagen über die anzeigende Einheit und über die Position des Mauszeigers macht. MouseInfo.getNumberOfButtons() liefert die Anzahl der Knöpfe.
Die Anzahl der Anwendungsfälle ist vielfältig. So ermöglicht dies zum Beispiel eine Farbpipette, mit der sich die Farbe eines Punktes nehmen lässt, der unter dem Mauszeiger steht.
while ( true )
{
Rectangle screenSize = new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
BufferedImage image = new Robot().createScreenCapture( screenSize );
Point location = MouseInfo.getPointerInfo().getLocation();
System.out.println( new Color( image.getRGB( location.x, location.y ) ) );
}
An den Ausgaben lassen sich gut die RGB-Bestandteile der Farbe ablesen.
Labels: Insel
Spielerei mit Javas dynamischer Bindung und überschatteten Attributen
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Mai 28, 2009.Werfen wir ein Blick auf folgendes Java-Programm:
class SuperBoaster
{
int nr = 1;
void boast()
{
System.out.println( "Ich bin die Nummber " + nr );
}
}
public class SubBoaster extends SuperBoaster
{
int nr = 2;
@Override void boast()
{
super.boast(); // Ich bin die Nummber 1
System.out.println( super.nr ); // 1
System.out.println( nr ); // 2
}
public static void main( String[] args )
{
new SubBoaster().boast();
}
}
Die Methode boast() aus SubBoaster ruft mit super.boast() die Methode der Oberklasse auf. Ein einfacher Aufruf von boast() in der Unterklasse würde in eine Rekursion führen. Die Unterklasse hat mit super.nr Zugriff auf die überschattete Objektvariable nr aus der Oberklasse. Es ist super wie this eine spezielle Referenz und kann auch genauso eingesetzt werden, nur das super in den Namensraum der Oberklasse geht.
Eine Aneinanderreihung von super-Schlüsselwörtern bei einer tieferen Vererbungshierarchie ist nicht möglich. Hinter einem super muss eine Objekteigenschaft stehen und Anweisungen wie super.super.nr sind somit immer ungültig.
Für Variablen gibt es eine Möglichkeit, die sich durch einen Cast in die Oberklasse ergibt. Setzen wir in boast() der Unterklasse folgende Anweisung
System.out.println( ((SuperBoaster) this).nr ); // 1
Die Ausgabe 1 ist also identisch mit System.out.println( super.nr ).
Die this-Referenz entspricht einem Objekt vom Typ SubBoaster. Wenn wir dies aber in den Typ SuperBoaster konvertieren, bekommen wir genau das nr aus der Basisklasse unserer Hierarchie. Wir erkennen hier eine sehr wichtige Eigenschaft von Java, nämlich, dass Variablen nicht dynamisch gebunden werden. Anders wäre es, wenn wir folgendes in die Methode boast()der Unterklasse SubBoaster setzen:
((SuperBoaster)this).boast();
Hier ruft die Laufzeitumgebung nicht boast() aus SuperBoaster auf, sondern die aktuelle Funktion boast(), aus SubBoaster sodass wir in einer Rekursion landen. Der Grund dafür liegt in der dynamischen Bindung zur Laufzeit, die ein Compiler-Typecast nicht ändert.
Labels: Insel
Bildschirmabzüge (Screenshots) und die Frage, ob der Benutzer etwas vor dem Bildschirm tut
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Mai 28, 2009.Eine sehr interessante Funktion der Robot-Klasse ist createScreenCapture(). Mit ihr lässt sich ein Bildschirmabzug (engl. screenshot) ohne Mauszeiger (zumindest unter Windows, Linux, Solaris und Mac OS X) machen. Die Funktion erwartet als Argument ein Rectangle-Objekt (speichert x, y, height und width), das den zu »fotografierenden« Bereich spezifiziert. Das Ergebnis von createScreenCapture() ist ein BufferedImage-Objekt, das direkt mit ImageIO in eine Datei kommen kann.
BufferedImage bi = new Robot().createScreenCapture(
new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) );
ImageIO.write( bi, "jpg", new File("c:/screenshot.jpg") );
Mit createScreenCapture() lassen sich sehr interessante Lösungen realisieren. So lässt sich zum Beispiel überwachen, ob sich Bildschirminhalte ändern. Mit einer Bildanalyse ließe sich auch herausfinden, was der Anwender sich gerade anschaut.
In einem kleinen Beispiel wollen wir feststellen, ob der Benutzer aktiv vom dem Bildschirm ist oder nicht. Wir machen dies an der Anzahl Pixel fest, die sich jede Sekunden verändern. Ein Programm soll dazu jede Sekunde ein Bildschirmabzug nehmen und ausgeben, um wie viel Prozent sich die Pixel gegenüber dem Vorgängerbild verändert haben.
package com.tutego.insel.ui.image;
import java.awt.*;
import java.awt.image.*;
public class ImageDiffs
{
public static void main( String args[] ) throws Exception
{
Rectangle screenSize = new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
BufferedImage image1 = new Robot().createScreenCapture( screenSize );
while ( true )
{
Thread.sleep( 1000 );
BufferedImage image2 = new Robot().createScreenCapture( screenSize );
DataBuffer dataBuffer1 = image1.getData().getDataBuffer();
DataBuffer dataBuffer2 = image2.getData().getDataBuffer();
int total = dataBuffer1.getSize(), diff = 0;
for ( int i = 0; i < total; i++ )
if ( dataBuffer1.getElem( i ) != dataBuffer2.getElem( i ) )
diff++;
System.out.printf( "Pixel total=%d, unterschiedliche Pixel=%d, Unterschied=%.2f%%%n",
total, diff, (double) 100 * diff / total );
image1 = image2;
}
}
}
Nach dem der Bildschirmabzug gemacht wurde, gilt es auf die Pixel zuzugreifen und die beiden Bilder zu vergleichen. Um das Bild abzulaufen, könnten wir entweder vom BufferedImage mit den Methode getRGB(int x, int y) arbeiten, oder uns – anders macht es getRGB() auch nicht – das Datenmodel der Grafik holen und es einfach komplett auflaufen; die Größe und Breite der beiden Bildschirmabzüge ist ja immer gleich, und so spielt die Höhe und Breite keine Rolle. Von den beiden DataBuffer-Objekten, die die Rohdaten der Grafik repräsentieren, erfragt getElem() den Farbwert und wenn es Unterschiede gibt, inkrementiert das Programm einen Zähler. Nach dem Ablaufen aller Werte gibt es eine Statistik, die etwa so beginnen kann:
Pixel total=2304000, unterschiedliche Pixel=297, Unterschied=0,01%
Pixel total=2304000, unterschiedliche Pixel=1708, Unterschied=0,07%
Pixel total=2304000, unterschiedliche Pixel=1689, Unterschied=0,07%
Pixel total=2304000, unterschiedliche Pixel=1000568, Unterschied=43,43%
Pixel total=2304000, unterschiedliche Pixel=1002525, Unterschied=43,51%
Pixel total=2304000, unterschiedliche Pixel=2087, Unterschied=0,09%
Labels: Insel

