Die kleinen Helfer von Eclipse

01. Februar 2010

Dass Eclipse vieles zum komfortablen Entwickeln bietet, dürfte jedem Entwickler klar sein. Sicherlich kennen viele die Möglichkeit, Getter und Setter generieren zu lassen, so dass einem eine Menge stupider Schreibarbeit erspart bleibt. Ebenfalls unter dem Menü Source (Shortcut: ALT+SHIFT+S) findet man weitere Möglichkeiten, um trivialen Code generieren zu lassen. Hierzu gehört z.B. das Erzeugen des Konstruktors, welcher alle Felder als Parameter hat. Interessant ist aber auf jeden Fall auch der toString-Generator. Wer kennt es nicht, wenn in den Log-Ausgaben kryptische Java-ReferenzIds stehen. Da wünscht man sich, man hätte toString() überschrieben, um ein paar mehr Informationen für die Fehlersuche zu bekommen. Wie bei den Getter und Setter Methoden, kann man sich die Schreibarbeit ersparen und einen Generator bemühen, der einem alle gewünschten Felder ausgibt. Ein großes Plus ist auch die Konfigurierbarkeit – man kann z.B. auch angeben, welchen Builder man für die Erzeugung des Strings nutzen möchte oder nach welchem Muster der String erzeugt werden soll.

toString-Methode generieren

Ein Blick lohnt sich auf jeden Fall!


Andreas Siepert

  • Share/Bookmark

Datum in Hibernate: Der Wolf(Timestamp) im Schafspelz(Date)

22. Januar 2010

Benutzt man Hibernate als OR-Mapper und will ein java.util.Date (Datum und Uhrzeit) speichern, ist Vorsicht geboten. Da java.sql.Timestamp von java.util.Date erbt, und der Typ in der Datenbank i.d.R. timestamp ist, bekommt man von Hibernate gegebenenfalls ein Timestamp-Objekt, und nicht ein Date-Objekt. Eigentlich kein Problem, doch die Klasse Timestamp ist …kaputt! Auszug aus dem Javadoc von Timestamp:

The Timestamp.equals(Object) method never returns true when passed a value of type java.util.Date because the nanos component of a date is unknown.

Will man zwei Dates vergleichen und befindet sich hinter der ersten Referenz ein Timestamp-Objekt, schlägt equals fehl.

Date d = new Date();
Date ts = new Timestamp(d.getTime());
System.out.println(ts.equals(d));    //returns false

Wie soll ich also zwei Dates miteinander vergleichen? Es wird noch schlimmer:

System.out.println(ts.compareTo(d)); // return 0
System.out.println(d.compareTo(ts)); // returns 1

Auch die compareTo-Methode ist fehlerhaft liefert ein anderes Ergebnis als erwartet. Schaut man sich den Konstruktor von Timstamp an, kommt man aus dem Staunen Entsetzen nicht mehr heraus. Die Klasse Date speichert das Datum millisekundengenau in dem Feld fastTime. Die Klasse Timestamp hingegen speichert das Datum sekundengenau in dem Feld fastTime und die Milli- und Nanosekunden im Feld nanos. Warum dies so ist, und nicht nur die Nanosekunden im Feld nanos gespeichert werden, ist mir ein Rätsel.

Will man nun ein Date und einen Timestamp miteinander vergleichen (z.B. auch mit before() und after()) schlägt dies fehl. Die compareTo-Methode von Date vergleicht die Millisekunden aus dem Feld fastTime, beim Timestamp-Objekt ist dies nur sekundengenau, die Millisekunden sind im Feld nanos gespeichert, und werden nicht berücksichtigt.

Dieses Problem tritt häufig in Verbindung mit Hibernate auf, die Schuld liegt aber bei der Standard Java-API. Allerdings lässt sich das Problem umgehen, indem man Hierbernate mit einem UserType zwingt, nur Objekte vom Typ Date zu liefern.

public class DateTimeType implements UserType {
    private static final int[] SQL_TYPES = new int[] {Types.TIMESTAMP};
    public DateTimeType() {
        super();
    }
 
    @SuppressWarnings("unchecked")
    public Class returnedClass() {
        return java.util.Date.class;
    }
 
    public int[] sqlTypes() {
        return SQL_TYPES;
    }
 
    public boolean equals(final Object x, final Object y) {
        if (x == y) {
            return true;
        }
        if (x == null || y == null) {
            return false;
        }
        Date xDate = (Date) x;
        Date yDate = (Date) y;
        return xDate.equals(yDate);
    }
 
    public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws SQLException {
        // extract Timestamp from the result set
        Timestamp timestamp = (Timestamp) Hibernate.TIMESTAMP.nullSafeGet(rs, names[0]);
        // return the value as a java.util.Date (dropping the nanoseconds)
        if (timestamp == null) {
            return null;
        } else {
            return new Date(timestamp.getTime());
        }
    }
 
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index) throws SQLException {
        // handle the NULL special case immediately
        if (value == null) {
            st.setTimestamp(index, null);
            return;
        }
        // make sure the received value is of the right type
        if (!Date.class.isAssignableFrom(value.getClass())) {
            throw new IllegalArgumentException("Received value is not a [java.util.Date] but [" + value.getClass() + "]");
        }
        // set the value into the resultset
        Timestamp tstamp = null;
        if (value instanceof Timestamp) {
            tstamp = (Timestamp) value;
        } else {
            tstamp = new Timestamp(((Date) value).getTime());
        }
        st.setTimestamp(index, tstamp);
    }
 
    public Object deepCopy(final Object value) {
        if (value == null) {
            return null;
        } else {
            return ((Date) value).clone();
        }
    }
 
    public boolean isMutable() {
        return true;
    }
 
    @Override
    public Object assemble(final Serializable cached, final Object owner) {
        return deepCopy(cached);
    }
 
    @Override
    public Serializable disassemble(final Object value) {
        return (Date) value;
    }
 
    @Override
    public int hashCode(final Object x) {
        return x.hashCode();
    }
 
    @Override
    public Object replace(final Object original, final Object target, final Object owner) {
        return deepCopy(original);
    }
}

Möglich ist eine Konfiguration auf Packet-Ebene, indem man eine package-info.java erstellt. Folgend die Konfiguration mit Annotationen auf Klassenebene:

@TypeDefs( {@TypeDef(name = "dateTimeType", typeClass = DateTimeType.class)})
public class MyBusinessObject {
 
    @Type(type = "dateTimeType")
    @Column(name = "time")
    private Date time;
    ...
}

Eventuell wird die freie Joda Time API in Java 1.7 die alten Datum und Kalendarklassen ersetzten. Bis dahin kann man mit diesem UserType sicher sein, dass Hibernate nur Date-Objekte zur Verfügung stellt, und somit kann man wieder equals und compareTo ohne Bedenken verwenden.
Siehe auch


Jan Kuenstler

  • Share/Bookmark

Buchvorstellung “Payback”

15. Januar 2010

Früher hatte dieser Blog ja mal den Untertitel “Technologie und ihre Folgen”. In diesem Sinne erlaube ich mir mal zur Abwechslung ein Buch vorzustellen, dass mir zum Jahreswechsel zwischen die Finger und unter die Augen gekommen ist.

Schirrmacher - PaybackEs handelt sich um das Buch “Payback” von Frank Schirrmacher.  Erschienen im Karl Blessing Verlag (16. November 2009).

Der Autor beschäftigt sich darin vorrangig mit der Frage, welche Auswirkungen die IT-Entwicklungen der letzten Jahre, insbesondere Vernetzung, WWW und Google, auf uns als Menschen haben. Dabei legt der Autor großen Wert darauf, dass er  kein grundsätzlicher Technologieskeptiker ist, der alle neuen Entwicklungen grundsätzlich ablehnt. Es geht auch nicht um Ablehnung, sondern vielmehr um kritische Beobachtung der Dinge, die um uns herum passieren und denen wir nicht entkommen können.

Warum ist dieses Buch nun etwas für diesen Blog? Wie der Autor ganz richtig bemerkt sind wir, die Softwareentwickler und Architekten, diejenigen, die mehr als jeder Andere Einfluss haben auf die Gestaltung unserer Welt. Hört sich massiv an, aber ist es nicht so? Wir sind die paar Prozent der Gesellschaft, die einerseits die technischen Rahmenbedinungen des WWW überhaupt verstehen aber auch ausbauen können. Also kann es ja nicht schaden, intelligente Gedanken zu diesem Thema zu hören und zu reflektieren.

Intelligente Gedanken sind ein gutes Stichwort: Das Buch ist definitiv nix für die intellektuelle Unterschicht. Bei amazon findet man Kommentare, dass der Autor zu viel schwallert und wichtigtuerisch fehlerhafte Thesen aufstellt. Der Sprachstil ist gepflegt gehoben und der Mann schreibt eben, wie ein Germanist schreibt. Aber man muss sagen: für einen Germanisten hat er erstaunlich viel verstanden.

Seine Beobachtungen von Rahmenbedingungen und Zusammenhängen finde ich recht interessant, auch wenn die eine oder andere Schlussfolgerung sicher in Frage zu stellen ist. Insbesondere zum Ende hin erwartet der Leser eine Art Lösungsvorschlag zu den angesprochenen Themen, der aber deutlich schwammiger (und rein von der Anzahl der Seiten im Buch kleiner) ausfällt, als die Feststellung der Ist-Situation. Somit bleibt ein etwas schaler Nachgeschmack, zumindest für mich als lösungsorientierten Menschen.

Unterm Strich möchte ich dieses Buch dennoch jedem empfehlen, der mal eine andere Sichtweise auf unsere tägliche Arbeit und unsere Welt gewinnen möchte. Ich habe viele bekannte Aspekte in dem Buch wiedergefunden und hatte Spaß an einem teils kritischen, teils interessanten und teils philosophischen Ausflug. Wie gesagt: für einen Germanisten hat er eine Menge verstanden.


Andreas Jene

  • Share/Bookmark

Eclipse Shortcuts Teil 2

08. Januar 2010

Eclipse verfügt über unzählige Shortcuts für nahezu alle Funktionen und Befehle. Jedes mal wenn ich auf der Suche nach neuen Shortcuts war, stieß ich auf lange unüberschaubare Listen. Es waren einfach zu viele neue Befehle um sich etwas zu merken. Neue Befehle habe ich fast nur durch abgucken gelernt. Auf diese Weise lerne ich nur einen neuen Shortcut, der mich dann auch gerade interessiert. Was bringen mir 100 Shortcuts, wenn ich vorher immer überlegen bzw. 2 mal probieren muss um den richtigen zu treffen. Da bleibe ich dann lieber “Mausschubser”.

Für diese Liste habe ich nun den Vormittag über jeden Shortcut, den ich benutzt habe in eine Datei getippt. Für diese Befehle brauche ich nicht nachdenken. Für alles andere verwende ich dann lieber die Maus.

STRG + d – Entfernen einer ganzen Zeile.

ALT + UP/DOWN – Verschieben der aktuellen Zeile nach oben oder unten.

ALT + LEFT/RIGHT – Springen zwischen den letzten bearbeiteten Zeilen.

STRG + 1 -Zeigt für die aktuelle Zeile die möglichen “quick fix” optionen an (z.b. Variable zuweisen, umbennen usw.). Für die meisten Optionen gibt es auch direkte Shortcuts aber die brauche ich mir so nicht merken. Nur durch diesen Shortcut ist diese Liste so kurz geblieben.

STRG + (SHIFT) + j – Suche im aktuellen Editor ohne Dialog. Diese Suche funktioniert ähnlich der Suche im Firefox. Nach dem drücken von STRG + J einfach das gesuchte Wort zu tippen. Im Editor wird dann nächsten möglichen Treffer gesprungen. Mit Shift wird die Suchrichtung geändert. Wiederholtes drücken spring zum nächsten möglichen Treffer.

STRG + SHIFT + t – Direktes öffnen einer Klasse. Neben ganzen Klassennamen können im Suchfeld auch nur die Großbuchstaben einer Klasse eingeben werden, wenn diese einen “Camel Case” Namen trägt (z.B. MTK für “MeineTestKlasse”, wenn es mehrere Treffer gibt dann funktioniert auch “MTKlas”).

STRG + SHIFT + r – Ähnlich der Suche einer Klasse, nur für beliebige Dateien.

STRG + SHIFT + g – “Java Search” für den markierten Code. Sehr hilfreich um Stellen zu finden, an denen eine Klasse verwendet oder eine Methode aufgerufen wird.

STRG + SPACE – Der Klassiker, kennt wohl wirklich jeder. Vervollständigung einer Methode, Klasse oder Variablen.

STRG + o – Zeigt innerhalb einer geöffneten Klasse alle darin befindlichen Methoden an, um dorthin springen zu können. Durch wiederholtes drücken können zusätzlich die geerbten Methoden angezeigt werden.

STRG + t – Zeigt auf einer Klasse die Vererbungshirarchie an, bzw. auf einer Methode die ggf. überschriebenen Methoden der Oberklassen an.

STRG + SHIFT + F – Formatieren der geöffneten Datei. Ist dank der Save Action nicht mehr wirklich notwendig. Ich brauche es nur noch für XML Dateien, da bei mir die Save Actions dort nicht ausgeführt werden.

STRG + 7 – Text aus/einkommentieren.

ALT + SHIFT + R – Umbennen einer Klasse Variablen oder Methode.

Speichern, also STRG + s braucht man ja eigentlich nicht mehr erwähnen. Bei vielen Entwicklern die ich kenne ist STRG + s ein Reflex und kein bewußter Befehl. Copy & Past benutze ich natürlich fast nie beim Entiwckeln ;-) .


Felix Breske

  • Share/Bookmark