import java.util.Date;
import java.util.Objects;
import java.util.Properties;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.sql.DataSource;
import org.h2.jdbcx.JdbcDataSource;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertFalse;
public class UpdateTimestampBug
{
private EntityManagerFactory factory;
@Before
public void setup()
{
JdbcDataSource ds = new JdbcDataSource();
ds.setURL( "jdbc:h2:./build/unittest-db" );
ds.setUser( "sa" );
ds.setPassword( "sa" );
factory = configureSessionFactory( ds );
}
@Test
public void test_HHH_11867_UpdateTimestamp()
throws Exception
{
String email1 = "test1@foo.bar";
String email2 = "test2@foo.bar";
long creationTime1;
long creationTime2;
long creationTime3;
long modificationTime1;
long modificationTime2;
long modificationTime3;
{
EntityManager em = newEntityManager();
em.getTransaction().begin();
Customer cust = new CustomerJpa( "5678" );
cust.setEmail( email1 );
em.persist( cust );
em.getTransaction().commit();
creationTime1 = cust.getCreatedAt().getTime();
modificationTime1 = cust.getModifiedAt().getTime();
em.close();
}
Thread.sleep( 37 );
{
EntityManager em = newEntityManager();
em.getTransaction().begin();
CustomerJpa customerJpa = em.find( CustomerJpa.class, "5678" );
assertThat( customerJpa, notNullValue() );
assertThat( customerJpa.getEmail(), equalTo( email1 ) );
customerJpa.setEmail( email2 );
em.flush();
em.getTransaction().commit();
creationTime2 = customerJpa.getCreatedAt().getTime();
modificationTime2 = customerJpa.getModifiedAt().getTime();
assertThat( customerJpa.getEmail(), equalTo( email2 ) );
em.close();
}
{
EntityManager em = newEntityManager();
em.getTransaction().begin();
CustomerJpa customerJpa = em.find( CustomerJpa.class, "5678" );
assertThat( customerJpa, notNullValue() );
assertThat( customerJpa, notNullValue() );
assertThat( customerJpa.getEmail(), equalTo( email2 ) );
creationTime3 = customerJpa.getCreatedAt().getTime();
modificationTime3 = customerJpa.getModifiedAt().getTime();
String message = "\n" +
" created 1: " + creationTime1 % 1000 + "\n" +
" created 2: " + creationTime2 % 1000 + "\n" +
" created 3: " + creationTime3 % 1000 + "\n" +
" modified 1: " + modificationTime1 % 1000 + "\n" +
"correct time >>> modified 2: " + modificationTime2 % 1000 + "\n" +
" wrong time >>> modified 3: " + modificationTime3 % 1000 + "\n";
assertFalse( message, customerJpa.getModifiedAt().equals( customerJpa.getCreatedAt() ) );
em.close();
}
}
private EntityManager newEntityManager()
{
return factory.createEntityManager();
}
private static SessionFactory configureSessionFactory( DataSource ds )
{
Properties props = new Properties();
props.put( Environment.DATASOURCE, ds );
props.put( Environment.DIALECT, "org.hibernate.dialect.H2Dialect" );
props.put( Environment.HBM2DDL_AUTO, "create" );
Configuration configuration = new Configuration();
configuration.addAnnotatedClass( CustomerJpa.class );
configuration.addProperties( props );
return configuration.buildSessionFactory();
}
public interface BusinessObject
{
String getIdentity();
Date getCreatedAt();
Date getModifiedAt();
}
public interface Person extends BusinessObject
{
}
@SuppressWarnings( "unused" )
public interface Customer extends Person
{
String getEmail();
void setEmail( String email );
}
@Entity
@Table( name = "customer" )
@SuppressWarnings( { "unused", "WeakerAccess" } )
public static class CustomerJpa extends AbstractPerson implements Customer
{
@Column( name = "email", length = 254 )
private String email;
public CustomerJpa()
{
super();
}
public CustomerJpa( String id )
{
super( id );
}
@Override
public String getEmail()
{
return email;
}
@Override
public void setEmail( String email )
{
this.email = email;
}
@Override
public String toString()
{
return "Customer{" + "id='" + identity + '\'' + ", email='" + email + '}';
}
}
@Entity( name = "person" )
@Inheritance( strategy = InheritanceType.JOINED )
public static class AbstractPerson extends AbstractBusinessObject implements Person
{
public AbstractPerson( String id )
{
super( id );
}
public AbstractPerson()
{
}
}
@MappedSuperclass
@SuppressWarnings( { "WeakerAccess" } )
public static abstract class AbstractBusinessObject
implements BusinessObject
{
@Id
@Column( name = "id" )
String identity;
@CreationTimestamp
@Temporal( TemporalType.TIMESTAMP )
@Column( name = "created_at", nullable = false, updatable = false )
private Date createdAt;
@UpdateTimestamp
@Temporal( TemporalType.TIMESTAMP )
@Column( name = "modified_at", nullable = false )
private Date modifiedAt;
@SuppressWarnings( "WeakerAccess" )
protected AbstractBusinessObject()
{
createdAt = new Date();
modifiedAt = new Date();
}
public AbstractBusinessObject( String identity )
{
this();
this.identity = identity;
}
public String getIdentity()
{
return identity;
}
@Override
public Date getCreatedAt()
{
return new Date( createdAt.getTime() ); }
@Override
public Date getModifiedAt()
{
return new Date( modifiedAt.getTime() ); }
@Override
public final boolean equals( Object o )
{
if( this == o )
{
return true;
}
if( !( o instanceof AbstractBusinessObject ) )
{
return false;
}
AbstractBusinessObject that = (AbstractBusinessObject) o;
return Objects.equals( identity, that.identity );
}
@Override
public final int hashCode()
{
return Objects.hash( identity );
}
@Override
public String toString()
{
return getClass().getSimpleName()
+ "[" + identity
+ ",created=" + createdAt
+ ",modified=" + modifiedAt +
']';
}
}
}