Google Android und die nicht-JVM
1 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Dezember 20, 2007.Google Android ist der Versuch von Google, ein quelloffenes und freies SDK für mobile Endgeräte zu etablieren. Nach ein paar Monaten gibt es die ersten Stimmen aus dem Netz, die nicht so positiv sind. Insbesondere werden die mangelhafte Dokumentation (damit meine ich nicht die "FAQ" http://code.google.com/android/kb/general.html), fehlende Beispiele und ein nicht öffentliches Issue/Bug-Tracking-System bemängelt. Interessant ist ebenfalls der Ansatz von Google, eine eigene JVM auszuliefern, um sich damit eventuell um Lizenzrechte rumzuwinden. Die Idee ist, den Java Quellcode zunächst über den Standard-Compiler in Java Bytecode zu übersetzen, aber dann über einen weiterer Präprozessor dx den JVM-Bytecode in das so genannte DEX-Format zu bringen, was die VM Dalvik dann ausführt. Dalvik ist etwas anders gebaut als die Standars-JVMs, denn es ist zum Beispiel eine Register-Maschine und keine Stack-Maschine. Ein weiteres Detail sind die Bibliotheken. Die Java Standard Library kommt vom Apache Harmony Projekt und ist somit Apache-Lizenz, genauso wie vieles von Android auch. (Das Betriebssystem unter der Haube ist Linux und somit GPL.)
Sehr große Anfrage an den JBuilder
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Dienstag, Dezember 18, 2007.In meiner Linksammlung sitzt http://www.borland.com/jbuilder, was mit der Browser nun beantwortet mit:
|
Server Error in '/' Application. |
Entweder geht es dem Produkt wahnsinnig gut und jeder will den JBuilder kaufen/laden/... oder .NET ist so schlecht, dass es mit der Last nicht umgehen kann.
Neuer LGPL PDF-Renderer von SwingLabs
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Samstag, Dezember 15, 2007.https://pdf-renderer.dev.java.net/ macht Suns schon länger vorhandenen PDF-Renderer unter der LGPL verfügbar. https://pdf-renderer.dev.java.net/source/browse/pdf-renderer/demos/viewer/com/sun/pdfview/PDFViewer.java?rev=1.3&view=markup zeigt an einem Beispiel, wie man die Komponente nutzen kann. Das viewer demo ist ein JNLP, um sich einen Überblick über die Möglichkeiten zu verschaffen. Ich habe das Hibernate-eBook mit 841 Seite geladen was überhaupt kein Problem war. Man blättert sehr flüssig und das Rendering ist schnell genug. Cool. Hm. Doch nicht soo cool. Als nächste ein O'Reilly eBook genommen; da steht alles auf dem Kopf und die Abstände passen überhaupt nicht. Apress Bücher sehen wieder super aus. Grrr. Und von http://www.absolit.de/PDF/Sonderdruck-Online-Marketing.pdf zeigt er die erste Seite (ohne Text) und die letzte Seite an -- der Rest ist weiß. Tja. Ob das so eine gute Lib ist hängt wohl von der Pdf ab. Vielleicht hat jmd. einen Tipp, ob ans der PDF-Version liegt, an den Fonts, ...
Labels: Open Source
Warum catch ( Exception e ) schlecht ist, und was man dagegen tun kann
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Dezember 13, 2007.private void setLaf()
{
try
{
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
}
catch ( ClassNotFoundException e )
{
handle();
}
catch ( InstantiationException e )
{
handle();
}
catch ( IllegalAccessException e )
{
handle();
}
catch ( UnsupportedLookAndFeelException e )
{
handle();
}
}
Oftmals befindet sich dann im Quellecode eine Anweisung wie catch ( Exception e ), die große Kaskaden von catch-Anweisungen verkleinern soll. (So kann man auch den gleichen Handler verwenden.) Das Problem dabei: Man fängt mehr, als man will, insbesondere wertvolle RuntimeExceptions, die man ungern als checked SQL- oder sonstwas-Exeption vernudelt haben möchte. Wenn ich mir moderne Frameworks, wie Spring oder Java EE 5 anschaue, wird dort ausschließlich mit RuntimeException gearbeitet, und die fängt eine catch ( Exception e ) ebenfalls brutal ab. Wenn zum Beispiel das Framework aufgrund einer unchecked Exception eine Transaktion abbricht, wir diesen Fehler aber schon „weggefangen“ haben, ist das ein echtes Problem.
Ich sehe für eine vernünftige Behandlung mehrere Möglichkeiten:
- Warten auf Java 3000, da dort sicherlich so etwas wie catch ( IOException, SQLException e ) definiert wird.
- Eine gemeinsame handle()-Funktion zu definieren, die man dann aus den catch-Handlern ansteuert.
- Ein catch ( Exception e ) und dann ein instanceof Test auf die erwarteten Exceptions mit einer re-thow, wenn der Typ nicht bekannt ist.
Beispiel für Apache Commons Events
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Dezember 13, 2007.
List<?> list = new ArrayList<String>();
ObservableList observedList = ObservableList.decorate( list );
observedList.getHandler().addPreModificationListener( new StandardPreModificationListener() {
public void modificationOccurring( StandardPreModificationEvent event )
{
if ( event.getType() == ModificationEventType.ADD )
System.out.println( event.getChangeObject() );
}
} );
observedList.add( "huhu" );
observedList.remove( 0 );
Die Bib ist schon älter, aber dennoch nur über die Versionsverwaltung zu bekommen. Schade eigentlich. Auch die Programm-API ist etwas "umständlich", und die Doku unvollständig.
Labels: Open Source
Schlechter Quellcode von NeuralBuild (NeuralLimits)
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Montag, Dezember 10, 2007.Über den Artikel http://entwickler.com/itr/news/psecom,neu,1,id,39010,nodeid,82.html bin ich auf einen Generator aufmerksam geworden, der automatisch DOAs und Transfer-Objekte erzeugt. Leider ist doch der generierte Quellcode wenig überzeugend. En Besipiel:
public Integer insertCompany(Company criteriaCompany)
throws NeuralBuildJavaSampleDAOInsertException {
Integer keyVal = new Integer(0);
con = connMgr.getConnection("neuralbuildjavasample");
int setindex = 1;
String vSQL = constructInsertPreparedStatement(criteriaCompany);
try {
PreparedStatement ps = con.prepareStatement(vSQL,
PreparedStatement.RETURN_GENERATED_KEYS);
if (criteriaCompany.CompanyID_isSet) {
ps.setInt(setindex, criteriaCompany.getCompanyID().intValue());
setindex++;
}
if (criteriaCompany.CompanyName_isSet) {
ps.setDate(setindex,
(java.sql.Date) criteriaCompany.getCompanyName());
setindex++;
}
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
keyVal = Integer.valueOf(rs.getObject(1).toString());
}
rs.close();
rs = null;
ps.close();
} catch (Exception e) {
connMgr.freeConnection("neuralbuildjavasample", con);
throw new NeuralBuildJavaSampleDAOInsertException("Insert Failed " +
e.getMessage(), e);
}
connMgr.freeConnection("neuralbuildjavasample", con);
return keyVal;
}
- new Integer(0) wird immer gebaut, auch wenn es später überschrieben wird.
- finally fehlt: So ist das close() nicht garantiert. (Nicht sooo schlimm, da bei Freigabe der Connection auch ResultSet und XXXStatement freigegeben werden.)
- Quellcode-Duplizierung bei connMgr.freeConnection("neuralbuildjavasample", con);. Das gehört auf jeden Fall in finally{}
- Was soll den rs = null; bewirken? Den GC hilt das bei lokalen Variablen nun wirklich nicht.
- catch (Exception e) muss wirklich sein? Ode doch catch (SQLException e)?
- Wenn die Rückgabe ein Integer-Objekt ist, warum dann "Integer.valueOf(rs.getObject(1).toString());" schreiben? Das funktioniert zwar, aber wenn getObject() schon in Integer ist, muss man nicht erst in ein String und dann wieder zurück konvertieren.
- Sollte man wirklich einfach nur 0 zurückliefern, wenn man keinen Schlüssel bekam?
Die anderen Methoden habe auch so ihre Macken, so mit der Namensgebung.
- CachedRowSet Rs = null; Groß-/Kleinschreibung!
- Gemische Groß-/Kleinschreibung ist Standard, nicht so bei setindex.
- Unterstriche sind von Sun in der Namenskonvention nur bei Konstanten vorgesehen, aber nicht etwa bei CompanyID_isSet
- Ist die Namensgebung so gut, wenn man liest
ps.setDate(setindex, (java.sql.Date) criteriaCompany.getCompanyName() );
Also setDate() auf ein Company-Name? - Die API-Doku sollte nicht schreiben: "Delete an object from the database." sondern laut Suns-JavaDoc-Vorgaben: "Deletes an object from the database."
"Whitespace cleanup on all sources" Java-Quellen endlich einheitlich
1 Kommentar(e). Veröffentlicht von Christian Ullenboom am Freitag, Dezember 07, 2007.Nach mehr als 10 Jahren sind in Java 7 endlich die Quellen so, dass nicht mehr Tabs und Spaces gemischt sind. Endlich. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6616089.
Die übelste Java-Implementierung für einen Schaltjahrtest...
1 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Dezember 06, 2007.... gibt es bei Worse than failure im Forum unter http://forums.worsethanfailure.com/forums/thread/31448.aspx.
JAXB2-Annotationen an Beispielen
1 Kommentar(e). Veröffentlicht von Christian Ullenboom am Donnerstag, Dezember 06, 2007.Schreiben der Felder statt Nutzen der Setter/Getter: Annotiere die Klasse mit
@XmlAccessorType( XmlAccessType.FIELD )
@XmlAttribute
| class Person { String name;
@XmlAttribute int id; } | <person id="123"> <name>Christian</name> </person> |
@XmlValue
Gibt es nur ein Element kann @XmlValue dies in den Rumpf setzten.
| class Person { int id; } | <person> <id>123</id> </person> |
| class Person { @XmlValue int id; } | <person>123</person> |
@Transient
Nimmt Element aus der XML-Abbildung aus.
| class Person { @XmlTransient int id;
String firstname; String lastname; } | <person> <firstname>Christian</firstname> <lastname>Ullenboom</lastname> </person> |
@XmlList
Schreibt Elemente einer Sammlung nicht in einzelnen Elementen, sondern mit Leerzeichen getrennt.
| class Person { List<String> emails; }
| <person> <emails>muh@kuh.de</emails> <emails>zick@zack.com</emails> </person>
|
| class Person { @XmlList List<String> emails; } | <person> <emails>muh@kuh.de zick@zack.com</emails> </person> |
Elemente einpacken mit @XmlElementWrapper
| class Person { List<String> emails; } | <person> <emails>muh@kuh.de</emails> <emails>zick@zack.com</emails> </person> |
| class Person { @XmlElementWrapper(name = "emails") @XmlElement(name = "email") List<String> emails; } | <person> <emails> <email>muh@kuh.de</email> <email>zick@zack.com</email> </emails> </person> |
Reihenfolge ändern
| class Person { String lastname, firstname; } | <person> <lastname>Ullenboom</lastname> <firstname>Christian</firstname> </person> |
| @XmlType( propOrder = { "firstname", "lastname" } ) class Person { String lastname, firstname; } | <person> <firstname>Christian</firstname> <lastname>Ullenboom</lastname> </person> |
@XmlJavaTypeAdapter
Anpassen der XML-Abbildung, etwa für Datumswerte.
| class Person { Date birthday; } | <person> <birthday>1973-03-12T00:00:00+01:00</birthday> </person> |
| class Person { @XmlJavaTypeAdapter( DateAdapter.class ) Date birthday; }
class DateAdapter extends XmlAdapter<String, Date> { private final static DateFormat formatter = new SimpleDateFormat( "dd/MM/yyyy" );
public Date unmarshal( String date ) throws ParseException { return formatter.parse( date ); }
public String marshal( Date date ) { return formatter.format( date ); } } | <person> <birthday>12/03/1973</birthday> </person> |
Der spezielle Datentyp XMLGregorianCalendar
Neben der Möglichkeit, Datumswerte mit einen XmlJavaTypeAdapter zu übersetzen, bietet JAXB den Datentype XMLGregorianCalendar.
Person p = new Person();
GregorianCalendar c = new GregorianCalendar( 1973, Calendar.MARCH, 12 );
p.birthday = DatatypeFactory.newInstance().newXMLGregorianCalendar( c );;
class Person { XMLGregorianCalendar birthday; } | <person> <birthday>1973-03-12T00:00:00.000+01:00</birthday> </person> |
Die Abbildung enthält alle notwendigen Werte. Sollen Segmente, wie die Zeitzone herausgenommen werden, so markiert man sie aus:
Person p = new Person();
GregorianCalendar c = new GregorianCalendar( 1973, Calendar.MARCH, 12 );
XMLGregorianCalendar gc = DatatypeFactory.newInstance().newXMLGregorianCalendar( c );
gc.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
gc.setTime(DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
p.birthday = gc;
class Person { XMLGregorianCalendar birthday; } | <person> <birthday>1973-03-12</birthday> </person> |
Elemente einbetten mit @XmlElements
Person p = new Person();
EmailContact c1 = new EmailContact();
c1.address = "hoho@weihnachtsmann.de";
PhoneContact c2 = new PhoneContact();
c2.number = "0011-123456789";
p.contacts = Arrays.asList( c1, c2 );
@XmlRootElement @XmlAccessorType( XmlAccessType.FIELD ) class Person { @XmlElements( { @XmlElement( name = "email", type = EmailContact.class ), @XmlElement( name = "phone", type = PhoneContact.class ) } ) List<Object> contacts = new ArrayList<Object>(); }
@XmlAccessorType( XmlAccessType.FIELD ) class EmailContact { @XmlValue String address; }
@XmlAccessorType( XmlAccessType.FIELD ) class PhoneContact { @XmlValue String number; } | <person> <email>hoho@weihnachtsmann.de</email> <phone>0011-123456789</phone> </person> |
JNotify: Was tut sich im Dateisystem?
2 Kommentar(e). Veröffentlicht von Christian Ullenboom am Samstag, Dezember 01, 2007.Die kleine (native) unter Linux und Windows arbeitende Bibliothek JNotify meldet Änderungen an Dateien. Ein Beispiel:
String path = "c:/";
int mask = JNotify.FILE_CREATED | JNotify.FILE_DELETED | JNotify.FILE_MODIFIED | JNotify.FILE_RENAMED;
boolean watchSubtree = true;
int watchID = JNotify.addWatch(path, mask, watchSubtree, new JNotifyListener()
{
@Override
public void fileCreated( int arg0, String arg1, String arg2 )
{
System.out.println( "created" );
}
@Override
public void fileDeleted( int arg0, String arg1, String arg2 )
{
System.out.println( "deleted" );
}
@Override
public void fileModified( int arg0, String arg1, String arg2 )
{
System.out.println( "modified" );
}
@Override
public void fileRenamed( int arg0, String arg1, String arg2, String arg3 )
{
System.out.println( "renamed" );
}
} );
Und am Ende:
JNotify.removeWatch(watchID);
Labels: Open Source
