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