Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.type.BasicType;
import org.hibernate.type.CharacterArrayClobType;
import org.hibernate.type.CharacterArrayNClobType;
import org.hibernate.type.CharacterNCharType;
Expand Down Expand Up @@ -532,10 +533,15 @@ public void fillSimpleValue() {
simpleValue.setTypeName( timeStampVersionType );
}

if ( simpleValue.getTypeName() != null && simpleValue.getTypeName().length() > 0
&& simpleValue.getMetadata().getTypeResolver().basic( simpleValue.getTypeName() ) == null ) {
if ( simpleValue.getTypeName() != null && simpleValue.getTypeName().length() > 0 ) {
try {
Class typeClass = buildingContext.getBootstrapContext().getClassLoaderAccess().classForName( simpleValue.getTypeName() );
BasicType basicType = simpleValue.getMetadata().getTypeResolver().basic( simpleValue.getTypeName() );

Class typeClass = ( basicType != null ) ?
basicType.getClass() :
buildingContext.getBootstrapContext()
.getClassLoaderAccess()
.classForName( simpleValue.getTypeName() );

if ( typeClass != null && DynamicParameterizedType.class.isAssignableFrom( typeClass ) ) {
Properties parameters = simpleValue.getTypeParameters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
import java.sql.Timestamp;
import java.util.Comparator;
import java.util.Date;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.java.JdbcTimestampTypeDescriptor;
import org.hibernate.type.descriptor.java.SerializableTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;
import org.hibernate.usertype.DynamicParameterizedType;

/**
* A type that maps between {@link java.sql.Types#TIMESTAMP TIMESTAMP} and {@link java.sql.Timestamp}
Expand All @@ -24,7 +27,7 @@
*/
public class TimestampType
extends AbstractSingleColumnStandardBasicType<Date>
implements VersionType<Date>, LiteralType<Date> {
implements VersionType<Date>, LiteralType<Date>, DynamicParameterizedType {

public static final TimestampType INSTANCE = new TimestampType();

Expand Down Expand Up @@ -70,4 +73,13 @@ public String objectToSQLString(Date value, Dialect dialect) throws Exception {
public Date fromStringValue(String xml) throws HibernateException {
return fromString( xml );
}

@Override
public void setParameterValues(Properties parameters) {
final ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE );

if ( reader != null ) {
setJavaTypeDescriptor( new JdbcTimestampTypeDescriptor( reader.getReturnedClass() ) );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;

/**
Expand Down Expand Up @@ -115,8 +116,11 @@ public Type heuristicType(String typeName) throws MappingException {
*/
public Type heuristicType(String typeName, Properties parameters) throws MappingException {
Type type = basic( typeName );

if ( type != null ) {
return type;
return ( type instanceof ParameterizedType ) ?
typeFactory.byClass( type.getClass(), parameters ) :
type;
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,18 @@ public Date deepCopyNotNull(Date value) {
}
}

private final boolean defaultToTimestamp;

public JdbcTimestampTypeDescriptor() {
super( Date.class, TimestampMutabilityPlan.INSTANCE );
defaultToTimestamp = true;
}

public JdbcTimestampTypeDescriptor(Class type) {
super( type, TimestampMutabilityPlan.INSTANCE );
defaultToTimestamp = false;
}

@Override
public String toString(Date value) {
return new SimpleDateFormat( TIMESTAMP_FORMAT ).format( value );
Expand Down Expand Up @@ -139,8 +148,12 @@ public <X> Date wrap(X value, WrapperOptions options) {
if ( value == null ) {
return null;
}

if ( Timestamp.class.isInstance( value ) ) {
return (Timestamp) value;
Timestamp timestampValue = (Timestamp) value;
return ( java.util.Date.class.equals( getJavaType() ) ) && !defaultToTimestamp ?
new Date( timestampValue.getTime() ) :
timestampValue;
}

if ( Long.class.isInstance( value ) ) {
Expand All @@ -152,7 +165,11 @@ public <X> Date wrap(X value, WrapperOptions options) {
}

if ( Date.class.isInstance( value ) ) {
return new Timestamp( ( (Date) value ).getTime() );
Date dateValue = (Date) value;

return ( java.util.Date.class.equals( getJavaType() ) ) ?
new Date( dateValue.getTime() ) :
new Timestamp( dateValue.getTime() );
}

throw unknownWrap( value.getClass() );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.hibernate.test.type;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;

import org.hibernate.testing.RequiresDialect;
import org.junit.Test;

import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;

/**
* @author Vlad Mihalcea
*/
public class TimestampRetainTypeTest extends BaseEntityManagerFunctionalTestCase {

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
UserAccount.class
};
}

@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
UserAccount user = new UserAccount()
.setId( 1L )
.setFirstName( "Vlad" )
.setLastName( "Mihalcea" )
.setSubscribedOn(
parseTimestamp("2013-09-29 12:30:00")
);

entityManager.persist( user );
} );

doInJPA( this::entityManagerFactory, entityManager -> {
UserAccount userAccount = entityManager.find(
UserAccount.class, 1L
);

assertEquals(
parseTimestamp("2013-09-29 12:30:00"),
userAccount.getSubscribedOn()
);

assertEquals( Date.class, userAccount.getSubscribedOn().getClass() );
} );
}

private final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss");

private java.util.Date parseTimestamp(String timestamp) {
try {
return DATE_TIME_FORMAT.parse(timestamp);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}

@Entity(name = "UserAccount")
@Table(name = "user_account")
public static class UserAccount {

@Id
private Long id;

@Column(name = "first_name", length = 50)
private String firstName;

@Column(name = "last_name", length = 50)
private String lastName;

@Column(name = "subscribed_on")
@Temporal(TemporalType.TIMESTAMP)
private Date subscribedOn;

public Long getId() {
return id;
}

public UserAccount setId(Long id) {
this.id = id;
return this;
}

public String getFirstName() {
return firstName;
}

public UserAccount setFirstName(String firstName) {
this.firstName = firstName;
return this;
}

public String getLastName() {
return lastName;
}

public UserAccount setLastName(String lastName) {
this.lastName = lastName;
return this;
}

public Date getSubscribedOn() {
return subscribedOn;
}

public UserAccount setSubscribedOn(Date subscribedOn) {
this.subscribedOn = subscribedOn;
return this;
}
}
}