Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is assertEquals false if it is the same date? Hibernate

I'm generating one date and saving in a database through hibernate, and when I get the value and I compare with the value before it was inserted. The result is not equal!

I created the date as following

Date rightnow = Calendar.getInstance().getTime();

Task t1 = new Task("My task", rightnow);
taskDao.saveOrUpdate(t1);

Task taskR1 = taskDao.get(t1.getIdTask());
assertEquals("They should have to be equal dates",taskR1.getDate(),t1.getDate());

I'm getting this error

<2014-04-11 23:13:13.0> is different to <Fri Apr 11 23:13:13 CEST 2014>

java.lang.AssertionError:  
They should have to be equal dates  
expected:<2014-04-11 23:13:13.0>  
but was:<Fri Apr 11 23:13:13 CEST 2014>

Extra info related with the problem

Class Task

@Entity
@Table(name = "t_task")
public class Task {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "idTask")
    private long idTask;
    ...
    @Column(name = "date")
    private Date date;
    ...

Mysql table t_task

CREATE TABLE IF NOT EXISTS `mytask`.`t_task` (
  `idTask` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `date` DATETIME NOT NULL
  ...

I created a new hashCode() and equals() functions in Task, with only date field and even so it is different.

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((date == null) ? 0 : date.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Task))
        return false;
    Task other = (Task) obj;
    if (date == null) {
        if (other.date != null)
            return false;
    } else if (!date.equals(other.date))
        return false;
    return true;
}

Any idea?

like image 519
Joe Avatar asked Apr 11 '14 20:04

Joe


People also ask

Does assertEquals use equals or ==?

The assert. equal() method tests if two values are equal, using the == operator. If the two values are not equal, an assertion failure is being caused, and the program is terminated.

What is the difference between assertSame and assertEquals?

assertEquals() Asserts that two objects are equal. assertSame() Asserts that two objects refer to the same object. the assertEquals should pass and assertSame should fail, as the value of both classes are equal but they have different reference location.

How does assert assertEquals work?

assertEquals. Asserts that two object arrays are equal. If they are not, an AssertionError is thrown with the given message. If expecteds and actuals are null , they are considered equal.

Can you use assertEquals for strings?

IIRC assertEquals() succeeds if both strings are null. If this is not what you want then call assertNotNull() as well.


1 Answers

This is a complete mess caused by the java.sql.Timestamp messed up design, and by Hibernate returning instances of this class. Indeed, you're storing a java.util.Date instance into your entity. Hibernate transforms that to a java.sql.Timestamp to insert it in the database. But when it reads the data from the database, it doesn't trasform back the Timestamp into a java.util.Date. That works fine, because Timestamp extends Date.

But Timestamp should never have extended Date. Indeed, Date is precise up to the millisecond, whereas Timestamp is precise up to the nanosecond. To be able to compare the nanoseconds parts of two Timestamp, Timestamp overrides the equals() method, but breaks its general contract by doing so. The end result is that you can have date.equals(timestamp) being true, but timestamp.equals(date) being false.

My advice: never compare Date instances with equals(). Use compareTo() instead.

like image 61
JB Nizet Avatar answered Oct 21 '22 18:10

JB Nizet