In der Hibernate Welt geschehen manchmal unerklärliche Dinge. In diesem Fall war es der
java.util.Date Typ einer Eigenschaft aus einer Hibernate Entity. Dieses Datumsfeld wurde für einen Vergleich mit einem anderen Datum herangezogen. Als Beispiel dient die Entity
Person mit dem Datumsfeld
#geburtstag. Die interessanten Dinge finden sich in (1) und (2). Bevor die Entity in der Datenbank angelegt wird, ist alles wie erwartet. Das
java.util.Date ist ein
java.util.Date. Der Vergleich liefert ebenfalls ein positives Ergebnis.
@Entity
@Table("PERSON")
public class Person {
@Id
@Column(name = "PERSON_ID")
private Long personId;
@Column(name = "NAME")
private String name;
@Column(name = "VORNAME")
private String vorname;
@Column(name = "GEBURTSTAG")
private java.util.Date geburtstag;
...
}
final Date date = new DateTime(2018, 5, 22, 17, 0, 0).toDate();
Person person = new Person();
person.setGeburtstag(date);
person.setName("Name");
person.setVorname("Vorname");
// (1) Vergleich vor #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isNotInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isEqualTo(date);
getSessionFactory().getCurrentSession().saveOrUpdate(person);
getSessionFactory().getCurrentSession().refresh(person);
// (2) Vergleich nach #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isNotEqualTo(date);
// IS NOT EQUAL, weil java.sql.Timestamp!
assertThat(now).isEqualTo(newRound.getDateTime());
// IS EQUAL! java.util.Date benutzt für den Vergleich long getTime()
Nach dem persistieren der Daten geschehen die bemerkenswerten Dinge. Aus dem
java.util.Date wird ein
java.sql.Timestamp. Das wäre nicht weiter tragisch, wenn nicht der Vergleich
assertThat(person.getGeburtstag()).isNotEqualTo(now); positiv ausfallen würde.
Was ist passiert? Mit dem
refresh wurde die Entity
Person neu aus der Datenbank gelesen, d.h. Hibernate liest per JDBC Verbindung die Daten aus der Datenbank. Für eine
Timestamp Spalte lautet der entsprechende JDBC Typ
java.sql.Timestamp, welcher von
java.util.Date abgeleitet ist. In der
#equals() Methode von
java.sql.Timestamp findet sich der Hinweis:
true if the given Object is an instance of a Timestamp that is equal
to this Timestamp object; false otherwise
D.h. ein Vergleich von
java.sql.Timestamp und
java.util.Date ist immer
false. Umgekehrt funktioniert der Vergleich:
assertThat(now).isEqualTo(newRound.getDateTime());, da java.util.Date#equals() für den Vergleich auf das Ergebnis der Methode
#getTime() zugreift. Das beste ist, man umgeht dieses Problem und verwendet gleich das
java.time.LocalDateTime aus JDK 8 oder höher. Falls diese Option nicht besteht, empfiehlt sich für den Vergleich die
#compare() Methode.
java.sql.Timestamp implementiert
#compare(Timestamp) und ein
#compare(Date).
Keine Kommentare:
Kommentar veröffentlichen