Java ist auch eine Insel

Donnerstag, Dezember 20, 2007

Google Android und die nicht-JVM

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.)

AddThis Social Bookmark Button

Dienstag, Dezember 18, 2007

Sehr große Anfrage an den JBuilder

In meiner Linksammlung sitzt http://www.borland.com/jbuilder, was mit der Browser nun beantwortet mit:

 

Server Error in '/' Application.

Server Too Busy

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Server Too Busy
Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[HttpException (0x80004005): Server Too Busy]
System.Web.HttpRuntime.RejectRequestInternal(HttpWorkerRequest wr) +148



Version Information: Microsoft .NET Framework Version:1.1.4322.2300; ASP.NET Version:1.1.4322.2300

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.

AddThis Social Bookmark Button

Samstag, Dezember 15, 2007

Neuer LGPL PDF-Renderer von SwingLabs

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, ...

AddThis Social Bookmark Button

Eclipse 3.4M4 - Nur wenig Neues

Unter New and Noteworthy findet man die üblichen Neuerungen. Für Plugin-Entwickler und in der Platform gibt es einige Neuerungen, für die JDT-Nutzer sind die Änderungen nicht sehr spektakulär. Interessanter sind:

Exportieren von Jar-Dateien, die man starten kann (also java -jar generated_file.jar)

Picture showing the runnable JAR export wizard

Suchoptionen, die man auf Attribute, Methoden, ... einschränken kann

Picture showing the match location selection UI

Unterscheidbare farbliche Hervorhebung für Lese- und Schreibzugriffe auf eine Variable

Picture showing read and write accesses in the Java editor

String-Konkatenation über + in StringBuffer-Kaskade umbauen

Picture showing the result of the 'Convert to StringBuffer' quick assist

Warum nicht gleich StringBuilder ab Java 5? Keine Ahnung.

Und der Download Eclipse 3.4M4.

Labels:

AddThis Social Bookmark Button

Donnerstag, Dezember 13, 2007

Warum catch ( Exception e ) schlecht ist, und was man dagegen tun kann

Eine ganze Reihe von Java-Methoden lösen eine ganze Reihe von unterschiedlichen Ausnahmen aus:

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.

AddThis Social Bookmark Button

Beispiel für Apache Commons Events

http://commons.apache.org/sandbox/events/ bietet Wrapper für java.util Datenstrukturen, um Ereignisse beim Zugriff zu senden.

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:

AddThis Social Bookmark Button

Montag, Dezember 10, 2007

Schlechter Quellcode von NeuralBuild (NeuralLimits)

Ü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."

AddThis Social Bookmark Button

Freitag, Dezember 07, 2007

"Whitespace cleanup on all sources" Java-Quellen endlich einheitlich

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.

AddThis Social Bookmark Button

Donnerstag, Dezember 06, 2007

Die übelste Java-Implementierung für einen Schaltjahrtest...

... gibt es bei Worse than failure im Forum unter http://forums.worsethanfailure.com/forums/thread/31448.aspx.

AddThis Social Bookmark Button

JAXB2-Annotationen an Beispielen

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>

AddThis Social Bookmark Button

Dienstag, Dezember 04, 2007

NetBeans 6 ist gelandet

Nach einer langen Zeit des Wartens ist NetBeans 6 offiziell. Die IDE teilt sich in 6 Versionen mit Unterschiedlichen Plugins und Zusatzsoftware auf; die größte Version mit allem Schnick und Schnack ist 169 MB groß und umfasst den Application-Server Glassfish und Tomcat. Die kleinste Java-IDE-Version ist 21 MB groß; wer mit NetBeans nur die Gui baut, kommt mit dieser Version gut hin. Überraschend finde ich, dass Sun voll auf Ruby geht, und dafür eine Extra-IDE zusammengebaut hat. Auch in der "All"-Version ist Ruby-Unterstützung inklusive. Sun könnte sich in meinem Augen etwas mehr für Groovy begeistern, aber vielleicht ist der Sonne das zu europäisch und zu wenig international.

Labels:

AddThis Social Bookmark Button

Samstag, Dezember 01, 2007

JNotify: Was tut sich im Dateisystem?

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:

AddThis Social Bookmark Button