[java] How to force Hibernate to return dates as java.util.Date instead of Timestamp?

Situation:

I have a persistable class with variable of java.util.Date type:

import java.util.Date;

@Entity
@Table(name = "prd_period")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Period extends ManagedEntity implements Interval {

   @Column(name = "startdate_", nullable = false)
   private Date startDate;

}

Corresponding table in DB:

CREATE TABLE 'prd_period' (
  'id_' bigint(20) NOT NULL AUTO_INCREMENT,
 ...
  'startdate_' datetime NOT NULL
)

Then I save my Period object to DB:

Period p = new Period();
Date d = new Date();
p.setStartDate();
myDao.save(p);

After then if I'm trying to extract my object from DB, it is returned with variable startDate of Timestamp type - and all the places where I'm trying to use equals(...) are returning false.

Question: are there any means to force Hibernate to return dates as object of java.util.Date type instead of Timestamp without explicit modification of every such variable (e.g it must be able just work, without explicit modification of existed variables of java.util.Date type)?

NOTE:

I found number of explicit solutions, where annotations are used or setter is modified - but I have many classes with Date-variables - so I need some centralized solution and all that described below is not good enough:

  1. Using annotation @Type: - java.sql.Date will be returned

    @Column
    @Type(type="date")
    private Date startDate;
    
  2. Using annotation @Temporal(TemporalType.DATE) - java.sql.Date will be returned

    @Temporal(TemporalType.DATE)
    @Column(name=”CREATION_DATE”)
    private Date startDate;
    
  3. By modifying setter (deep copy) - java.util.Date will be returned

    public void setStartDate(Date startDate) {
        if (startDate != null) {
            this.startDate = new Date(startDate.getTime());
        } else {
            this.startDate = null;
        }
    }
    
  4. By creation of my own type: - java.util.Date will be returned

Details are given here: http://blogs.sourceallies.com/2012/02/hibernate-date-vs-timestamp/

This question is related to java hibernate jpa mapping

The answer is


A simple alternative to using a custom UserType is to construct a new java.util.Date in the setter for the date property in your persisted bean, eg:

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Column;

@Entity
public class Purchase {

    private Date date;

    @Column
    public Date getDate() {
        return this.date;
    }

    public void setDate(Date date) {
        // force java.sql.Timestamp to be set as a java.util.Date
        this.date = new Date(date.getTime());
    }

}

Here is solution for Hibernate 4.3.7.Final.

pacakge-info.java contains

@TypeDefs(
    {
        @TypeDef(
                name = "javaUtilDateType",
                defaultForType = java.util.Date.class,
                typeClass = JavaUtilDateType.class
        )
    })
package some.pack;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

And JavaUtilDateType:

package some.other.or.same.pack;

import java.sql.Timestamp;
import java.util.Comparator;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.LiteralType;
import org.hibernate.type.StringType;
import org.hibernate.type.TimestampType;
import org.hibernate.type.VersionType;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JdbcTimestampTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;

/**
 * Note: Depends on hibernate implementation details hibernate-core-4.3.7.Final.
 *
 * @see
 * <a href="http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch06.html#types-custom">Hibernate
 * Documentation</a>
 * @see TimestampType
 */
public class JavaUtilDateType
        extends AbstractSingleColumnStandardBasicType<Date>
        implements VersionType<Date>, LiteralType<Date> {

    public static final TimestampType INSTANCE = new TimestampType();

    public JavaUtilDateType() {
        super(
                TimestampTypeDescriptor.INSTANCE,
                new JdbcTimestampTypeDescriptor() {

                    @Override
                    public Date fromString(String string) {
                        return new Date(super.fromString(string).getTime());
                    }

                    @Override
                    public <X> Date wrap(X value, WrapperOptions options) {
                        return new Date(super.wrap(value, options).getTime());
                    }

                }
        );
    }

    @Override
    public String getName() {
        return "timestamp";
    }

    @Override
    public String[] getRegistrationKeys() {
        return new String[]{getName(), Timestamp.class.getName(), java.util.Date.class.getName()};
    }

    @Override
    public Date next(Date current, SessionImplementor session) {
        return seed(session);
    }

    @Override
    public Date seed(SessionImplementor session) {
        return new Timestamp(System.currentTimeMillis());
    }

    @Override
    public Comparator<Date> getComparator() {
        return getJavaTypeDescriptor().getComparator();
    }

    @Override
    public String objectToSQLString(Date value, Dialect dialect) throws Exception {
        final Timestamp ts = Timestamp.class.isInstance(value)
                ? (Timestamp) value
                : new Timestamp(value.getTime());
        // TODO : use JDBC date literal escape syntax? -> {d 'date-string'} in yyyy-mm-dd hh:mm:ss[.f...] format
        return StringType.INSTANCE.objectToSQLString(ts.toString(), dialect);
    }

    @Override
    public Date fromStringValue(String xml) throws HibernateException {
        return fromString(xml);
    }
}

This solution mostly relies on TimestampType implementation with adding additional behaviour through anonymous class of type JdbcTimestampTypeDescriptor.


I ran into a problem with this as well as my JUnit assertEquals were failing comparing Dates to Hibernate emitted 'java.util.Date' types (which as described in the question are really Timestamps). It turns out that by changing the mapping to 'date' rather than 'java.util.Date' Hibernate generates java.util.Date members. I am using an XML mapping file with Hibernate version 4.1.12.

This version emits 'java.util.Timestamp':

<property name="date" column="DAY" type="java.util.Date" unique-key="KONSTRAINT_DATE_IDX" unique="false" not-null="true" />

This version emits 'java.util.Date':

<property name="date" column="DAY" type="date" unique-key="KONSTRAINT_DATE_IDX" unique="false" not-null="true" />

Note, however, if Hibernate is used to generate the DDL, then these will generate different SQL types (Date for 'date' and Timestamp for 'java.util.Date').


Approaches 1 and 2 obviously don't work, because you get java.sql.Date objects, per JPA/Hibernate spec, and not java.util.Date. From approaches 3 and 4, I would rather choose the latter one, because it's more declarative, and will work with both field and getter annotations.

You have already laid out the solution 4 in your referenced blog post, as @tscho was kind to point out. Maybe defaultForType (see below) should give you the centralized solution you were looking for. Of course will will still need to differentiate between date (without time) and timestamp fields.

For future reference I will leave the summary of using your own Hibernate UserType here:

To make Hibernate give you java.util.Date instances, you can use the @Type and @TypeDef annotations to define a different mapping of your java.util.Date java types to and from the database.

See the examples in the core reference manual here.

  1. Implement a UserType to do the actual plumbing (conversion to/from java.util.Date), named e.g. TimestampAsJavaUtilDateType
  2. Add a @TypeDef annotation on one entity or in a package-info.java - both will be available globally for the session factory (see manual link above). You can use defaultForType to apply the type conversion on all mapped fields of type java.util.Date.

    @TypeDef
      name = "timestampAsJavaUtilDate",
      defaultForType = java.util.Date.class, /* applied globally */
      typeClass = TimestampAsJavaUtilDateType.class
    )
    
  3. Optionally, instead of defaultForType, you can annotate your fields/getters with @Type individually:

    @Entity
    public class MyEntity {
       [...]
       @Type(type="timestampAsJavaUtilDate")
       private java.util.Date myDate;
       [...]
    }
    

P.S. To suggest a totally different approach: we usually just don't compare Date objects using equals() anyway. Instead we use a utility class with methods to compare e.g. only the calendar date of two Date instances (or another resolution such as seconds), regardless of the exact implementation type. That as worked well for us.


There are some classes in the Java platform libraries that do extend an instantiable class and add a value component. For example, java.sql.Timestamp extends java.util.Date and adds a nanoseconds field. The equals implementation for Timestamp does violate symmetry and can cause erratic behavior if Timestamp and Date objects are used in the same collection or are otherwise intermixed. The Timestamp class has a disclaimer cautioning programmers against mixing dates and timestamps. While you won’t get into trouble as long as you keep them separate, there’s nothing to prevent you from mixing them, and the resulting errors can be hard to debug. This behavior of the Timestamp class was a mistake and should not be emulated.

check out this link

http://blogs.sourceallies.com/2012/02/hibernate-date-vs-timestamp/


Just add the this annotation @Temporal(TemporalType.DATE) for a java.util.Date field in your entity class.

More information available in this stackoverflow answer.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to hibernate

Hibernate Error executing DDL via JDBC Statement How does spring.jpa.hibernate.ddl-auto property exactly work in Spring? Error creating bean with name 'entityManagerFactory' defined in class path resource : Invocation of init method failed JPA Hibernate Persistence exception [PersistenceUnit: default] Unable to build Hibernate SessionFactory Disable all Database related auto configuration in Spring Boot Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] HikariCP - connection is not available Hibernate-sequence doesn't exist How to find distinct rows with field in list using JPA and Spring? Spring Data JPA and Exists query

Examples related to jpa

No converter found capable of converting from type to type How does spring.jpa.hibernate.ddl-auto property exactly work in Spring? Deserialize Java 8 LocalDateTime with JacksonMapper Error creating bean with name 'entityManagerFactory' defined in class path resource : Invocation of init method failed How to beautifully update a JPA entity in Spring Data? JPA Hibernate Persistence exception [PersistenceUnit: default] Unable to build Hibernate SessionFactory How to return a custom object from a Spring Data JPA GROUP BY query How to find distinct rows with field in list using JPA and Spring? What is this spring.jpa.open-in-view=true property in Spring Boot? Spring Data JPA and Exists query

Examples related to mapping

Elasticsearch : Root mapping definition has unsupported parameters index : not_analyzed When do you use map vs flatMap in RxJava? How do you create nested dict in Python? Best Practices for mapping one object to another Create a map with clickable provinces/states using SVG, HTML/CSS, ImageMap Deserialize JSON to ArrayList<POJO> using Jackson How to force Hibernate to return dates as java.util.Date instead of Timestamp? Entity framework code-first null foreign key Mapping many-to-many association table with extra column(s) Mapping object to dictionary and vice versa