diff --git a/core/src/main/java/org/hibernate/annotations/Source.java b/core/src/main/java/org/hibernate/annotations/Source.java new file mode 100644 index 0000000000..30c8b64bb8 --- /dev/null +++ b/core/src/main/java/org/hibernate/annotations/Source.java @@ -0,0 +1,44 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +package org.hibernate.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Optional annotation in conjunction with {@link javax.persistence.Version} and timestamp version properties. + * The annotation value decides where the timestamp is generated. + * + * @author Hardy Ferentschik + */ +@Target({ METHOD, FIELD }) +@Retention(RUNTIME) +public @interface Source { + SourceType value() default SourceType.VM; +} diff --git a/core/src/main/java/org/hibernate/annotations/SourceType.java b/core/src/main/java/org/hibernate/annotations/SourceType.java new file mode 100644 index 0000000000..9bab2753da --- /dev/null +++ b/core/src/main/java/org/hibernate/annotations/SourceType.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +package org.hibernate.annotations; + +/** + * Where should Hibernate retrieve the value from? From the database, or from the current JVM? + * + * @author Hardy Ferentschik + */ +public enum SourceType { + /** + * Get the timestamp from the current VM. + * @see + */ + VM("timestamp"), + + /** + * Get the timestamp from the database. + */ + DB("dbtimestamp"); + + private final String typeName; + + SourceType(String typeName ) { + this.typeName = typeName; + } + + public String typeName() { + return typeName; + } +} diff --git a/core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 1069491fdc..b7fc3d5a88 100644 --- a/core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -124,6 +124,7 @@ import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Parent; import org.hibernate.annotations.Proxy; import org.hibernate.annotations.Sort; +import org.hibernate.annotations.Source; import org.hibernate.annotations.Tuplizer; import org.hibernate.annotations.Tuplizers; import org.hibernate.annotations.TypeDef; @@ -372,26 +373,26 @@ public final class AnnotationBinder { idGen.setIdentifierGeneratorStrategy( org.hibernate.id.enhanced.TableGenerator.class.getName() ); idGen.addParam( org.hibernate.id.enhanced.TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, "true" ); - if ( !BinderHelper.isDefault( tabGen.catalog() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.catalog() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.CATALOG, tabGen.catalog() ); } - if ( !BinderHelper.isDefault( tabGen.schema() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.schema() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.SCHEMA, tabGen.schema() ); } - if ( !BinderHelper.isDefault( tabGen.table() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.table() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.TABLE_PARAM, tabGen.table() ); } - if ( !BinderHelper.isDefault( tabGen.pkColumnName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnName() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.SEGMENT_COLUMN_PARAM, tabGen.pkColumnName() ); } - if ( !BinderHelper.isDefault( tabGen.pkColumnValue() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnValue() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.SEGMENT_VALUE_PARAM, tabGen.pkColumnValue() ); } - if ( !BinderHelper.isDefault( tabGen.valueColumnName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.valueColumnName() ) ) { idGen.addParam( org.hibernate.id.enhanced.TableGenerator.VALUE_COLUMN_PARAM, tabGen.valueColumnName() ); @@ -412,13 +413,13 @@ public final class AnnotationBinder { else { idGen.setIdentifierGeneratorStrategy( MultipleHiLoPerTableGenerator.class.getName() ); - if ( !BinderHelper.isDefault( tabGen.table() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.table() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.ID_TABLE, tabGen.table() ); } - if ( !BinderHelper.isDefault( tabGen.catalog() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.catalog() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.CATALOG, tabGen.catalog() ); } - if ( !BinderHelper.isDefault( tabGen.schema() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.schema() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.SCHEMA, tabGen.schema() ); } //FIXME implement uniqueconstrains @@ -426,13 +427,13 @@ public final class AnnotationBinder { log.warn( "Ignoring unique constraints specified on table generator [{}]", tabGen.name() ); } - if ( !BinderHelper.isDefault( tabGen.pkColumnName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnName() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.PK_COLUMN_NAME, tabGen.pkColumnName() ); } - if ( !BinderHelper.isDefault( tabGen.valueColumnName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.valueColumnName() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME, tabGen.valueColumnName() ); } - if ( !BinderHelper.isDefault( tabGen.pkColumnValue() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tabGen.pkColumnValue() ) ) { idGen.addParam( MultipleHiLoPerTableGenerator.PK_VALUE_NAME, tabGen.pkColumnValue() ); } idGen.addParam( TableHiLoGenerator.MAX_LO, String.valueOf( tabGen.allocationSize() - 1 ) ); @@ -445,13 +446,13 @@ public final class AnnotationBinder { if ( useNewGeneratorMappings ) { idGen.setIdentifierGeneratorStrategy( SequenceStyleGenerator.class.getName() ); - if ( !BinderHelper.isDefault( seqGen.catalog() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( seqGen.catalog() ) ) { idGen.addParam( SequenceStyleGenerator.CATALOG, seqGen.catalog() ); } - if ( !BinderHelper.isDefault( seqGen.schema() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( seqGen.schema() ) ) { idGen.addParam( SequenceStyleGenerator.SCHEMA, seqGen.schema() ); } - if ( !BinderHelper.isDefault( seqGen.sequenceName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( seqGen.sequenceName() ) ) { idGen.addParam( SequenceStyleGenerator.SEQUENCE_PARAM, seqGen.sequenceName() ); } idGen.addParam( SequenceStyleGenerator.INCREMENT_PARAM, String.valueOf( seqGen.allocationSize() ) ); @@ -460,7 +461,7 @@ public final class AnnotationBinder { else { idGen.setIdentifierGeneratorStrategy( "seqhilo" ); - if ( !BinderHelper.isDefault( seqGen.sequenceName() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( seqGen.sequenceName() ) ) { idGen.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, seqGen.sequenceName() ); } //FIXME: work on initialValue() through SequenceGenerator.PARAMETERS @@ -658,7 +659,7 @@ public final class AnnotationBinder { SimpleValue key = new DependantValue( mappings, jsc.getTable(), jsc.getIdentifier() ); jsc.setKey( key ); ForeignKey fk = clazzToProcess.getAnnotation( ForeignKey.class ); - if ( fk != null && !BinderHelper.isDefault( fk.name() ) ) { + if ( fk != null && !BinderHelper.isEmptyAnnotationValue( fk.name() ) ) { key.setForeignKeyName( fk.name() ); } if ( onDeleteAnn != null ) { @@ -1302,14 +1303,14 @@ public final class AnnotationBinder { params.setProperty( param.name(), param.value() ); } - if ( BinderHelper.isDefault( defAnn.name() ) && defAnn.defaultForType().equals( void.class ) ) { + if ( BinderHelper.isEmptyAnnotationValue( defAnn.name() ) && defAnn.defaultForType().equals( void.class ) ) { throw new AnnotationException( "Either name or defaultForType (or both) attribute should be set in TypeDef having typeClass " + defAnn.typeClass().getName() ); } - if ( !BinderHelper.isDefault( defAnn.name() ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( defAnn.name() ) ) { log.info( "Binding type definition: {}", defAnn.name() ); mappings.addTypeDef( defAnn.name(), defAnn.typeClass().getName(), params ); } @@ -1501,7 +1502,7 @@ public final class AnnotationBinder { RootClass rootClass = ( RootClass ) propertyHolder.getPersistentClass(); propertyBinder.setColumns( columns ); Property prop = propertyBinder.makePropertyValueAndBind(); - propertyBinder.getSimpleValueBinder().setVersion( true ); + setVersionInformation( property, propertyBinder ); rootClass.setVersion( prop ); //If version is on a mapped superclass, update the mapping @@ -2088,6 +2089,14 @@ public final class AnnotationBinder { } } + private static void setVersionInformation(XProperty property, PropertyBinder propertyBinder) { + propertyBinder.getSimpleValueBinder().setVersion( true ); + if(property.isAnnotationPresent( Source.class )) { + Source source = property.getAnnotation( Source.class ); + propertyBinder.getSimpleValueBinder().setTimestampVersionType( source.value().typeName() ); + } + } + private static void processId( PropertyHolder propertyHolder, PropertyData inferredData, @@ -2174,13 +2183,13 @@ public final class AnnotationBinder { collectionBinder.setExplicitAssociationTable( true ); - if ( !BinderHelper.isDefault( schema ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( schema ) ) { associationTableBinder.setSchema( schema ); } - if ( !BinderHelper.isDefault( catalog ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( catalog ) ) { associationTableBinder.setCatalog( catalog ); } - if ( !BinderHelper.isDefault( tableName ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( tableName ) ) { associationTableBinder.setName( tableName ); } associationTableBinder.setUniqueConstraints( uniqueConstraints ); @@ -2605,7 +2614,7 @@ public final class AnnotationBinder { String fkName = fk != null ? fk.name() : ""; - if ( !BinderHelper.isDefault( fkName ) ) { + if ( !BinderHelper.isEmptyAnnotationValue( fkName ) ) { value.setForeignKeyName( fkName ); } @@ -2739,7 +2748,7 @@ public final class AnnotationBinder { } } } - if ( trueOneToOne || mapToPK || !BinderHelper.isDefault( mappedBy ) ) { + if ( trueOneToOne || mapToPK || !BinderHelper.isEmptyAnnotationValue( mappedBy ) ) { //is a true one-to-one //FIXME referencedColumnName ignored => ordering may fail. OneToOneSecondPass secondPass = new OneToOneSecondPass( @@ -2754,7 +2763,7 @@ public final class AnnotationBinder { } else { mappings.addSecondPass( - secondPass, BinderHelper.isDefault( mappedBy ) + secondPass, BinderHelper.isEmptyAnnotationValue( mappedBy ) ); } } diff --git a/core/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java b/core/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java index 26bafc19dd..801f2a4cef 100644 --- a/core/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java +++ b/core/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java @@ -76,6 +76,7 @@ public class SimpleValueBinder { private Table table; private SimpleValue simpleValue; private boolean isVersion; + private String timeStampVersionType; //is a Map key private boolean key; private String referencedEntityName; @@ -92,6 +93,10 @@ public class SimpleValueBinder { this.isVersion = isVersion; } + public void setTimestampVersionType(String versionType) { + this.timeStampVersionType = versionType; + } + public void setPropertyName(String propertyName) { this.propertyName = propertyName; } @@ -114,8 +119,11 @@ public class SimpleValueBinder { } //TODO execute it lazily to be order safe + public void setType(XProperty property, XClass returnedClass) { - if ( returnedClass == null ) return; //we cannot guess anything + if ( returnedClass == null ) { + return; + } //we cannot guess anything XClass returnedClassOrElement = returnedClass; boolean isArray = false; if ( property.isArray() ) { @@ -125,8 +133,8 @@ public class SimpleValueBinder { Properties typeParameters = this.typeParameters; typeParameters.clear(); String type = BinderHelper.ANNOTATION_STRING_DEFAULT; - if ( (!key && property.isAnnotationPresent( Temporal.class ) ) - || (key && property.isAnnotationPresent( MapKeyTemporal.class ) )) { + if ( ( !key && property.isAnnotationPresent( Temporal.class ) ) + || ( key && property.isAnnotationPresent( MapKeyTemporal.class ) ) ) { boolean isDate; if ( mappings.getReflectionManager().equals( returnedClassOrElement, Date.class ) ) { @@ -154,7 +162,8 @@ public class SimpleValueBinder { + StringHelper.qualify( persistentClassName, propertyName ) ); } - break; case TIMESTAMP: + break; + case TIMESTAMP: type = isDate ? "timestamp" : "calendar"; break; default: @@ -237,7 +246,7 @@ public class SimpleValueBinder { private javax.persistence.EnumType getEnumType(XProperty property) { javax.persistence.EnumType enumType = null; - if (key) { + if ( key ) { MapKeyEnumerated enumAnn = property.getAnnotation( MapKeyEnumerated.class ); if ( enumAnn != null ) { enumType = enumAnn.value(); @@ -253,7 +262,7 @@ public class SimpleValueBinder { } private TemporalType getTemporalType(XProperty property) { - if (key) { + if ( key ) { MapKeyTemporal ann = property.getAnnotation( MapKeyTemporal.class ); return ann.value(); } @@ -266,13 +275,14 @@ public class SimpleValueBinder { public void setExplicitType(String explicitType) { this.explicitType = explicitType; } - + //FIXME raise an assertion failure if setExplicitType(String) and setExplicitType(Type) are use at the same time + public void setExplicitType(Type typeAnn) { if ( typeAnn != null ) { explicitType = typeAnn.type(); typeParameters.clear(); - for (Parameter param : typeAnn.parameters()) { + for ( Parameter param : typeAnn.parameters() ) { typeParameters.setProperty( param.name(), param.value() ); } } @@ -288,7 +298,7 @@ public class SimpleValueBinder { } public SimpleValue make() { - + validate(); log.debug( "building SimpleValue for {}", propertyName ); if ( table == null ) { @@ -299,10 +309,10 @@ public class SimpleValueBinder { linkWithValue(); boolean isInSecondPass = mappings.isInSecondPass(); - SetSimpleValueTypeSecondPass secondPass = new SetSimpleValueTypeSecondPass(this); - if (!isInSecondPass) { + SetSimpleValueTypeSecondPass secondPass = new SetSimpleValueTypeSecondPass( this ); + if ( !isInSecondPass ) { //Defer this to the second pass - mappings.addSecondPass(secondPass); + mappings.addSecondPass( secondPass ); } else { //We are already in second pass @@ -312,23 +322,25 @@ public class SimpleValueBinder { } public void linkWithValue() { - if ( columns[0].isNameDeferred() && ! mappings.isInSecondPass() && referencedEntityName != null) { + if ( columns[0].isNameDeferred() && !mappings.isInSecondPass() && referencedEntityName != null ) { mappings.addSecondPass( - new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, ( Ejb3JoinColumn[]) columns, simpleValue) + new PkDrivenByDefaultMapsIdSecondPass( + referencedEntityName, ( Ejb3JoinColumn[] ) columns, simpleValue + ) ); } else { - for ( Ejb3Column column : columns) { + for ( Ejb3Column column : columns ) { column.linkWithValue( simpleValue ); } } } public void fillSimpleValue() { - - log.debug( "setting SimpleValue typeName for {}", propertyName ); - - String type = BinderHelper.isDefault( explicitType ) ? returnedClassName : explicitType; + + log.debug( "Setting SimpleValue typeName for {}", propertyName ); + + String type = BinderHelper.isEmptyAnnotationValue( explicitType ) ? returnedClassName : explicitType; org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type ); if ( typeDef != null ) { type = typeDef.getTypeClass(); @@ -342,11 +354,15 @@ public class SimpleValueBinder { if ( persistentClassName != null ) { simpleValue.setTypeUsingReflection( persistentClassName, propertyName ); } - - if ( !simpleValue.isTypeSpecified() && isVersion()) { + + if ( !simpleValue.isTypeSpecified() && isVersion() ) { simpleValue.setTypeName( "integer" ); } - + + // HHH-5205 + if ( timeStampVersionType != null ) { + simpleValue.setTypeName( timeStampVersionType ); + } } public void setKey(boolean key) { diff --git a/testsuite/src/test/java/org/hibernate/test/annotations/various/DBTimestamped.java b/testsuite/src/test/java/org/hibernate/test/annotations/various/DBTimestamped.java new file mode 100644 index 0000000000..be616f123e --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/annotations/various/DBTimestamped.java @@ -0,0 +1,67 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +// $Id:$ +package org.hibernate.test.annotations.various; + +import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Version; + +import org.hibernate.annotations.Source; +import org.hibernate.annotations.SourceType; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class DBTimestamped { + @Id + @GeneratedValue + private int id; + + @Version + @Source(SourceType.DB) + private Date lastUpdate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } +} + + diff --git a/testsuite/src/test/java/org/hibernate/test/annotations/various/TimestampTest.java b/testsuite/src/test/java/org/hibernate/test/annotations/various/TimestampTest.java new file mode 100644 index 0000000000..ce5e1eb10c --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/annotations/various/TimestampTest.java @@ -0,0 +1,67 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +//$Id$ +package org.hibernate.test.annotations.various; + +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.metadata.ClassMetadata; +import org.hibernate.test.annotations.TestCase; +import org.hibernate.type.DbTimestampType; +import org.hibernate.type.TimestampType; + +/** + * Test for the @Timestamp annotation. + * + * @author Hardy Ferentschik + */ +public class TimestampTest extends TestCase { + + public void testTimestampSourceIsVM() throws Exception { + assertTimestampSource( VMTimestamped.class, TimestampType.class ); + } + + public void testTimestampSourceIsDB() throws Exception { + assertTimestampSource( DBTimestamped.class, DbTimestampType.class ); + } + + private void assertTimestampSource(Class clazz, Class expectedTypeClass) throws Exception { + buildConfiguration(); + ClassMetadata meta = sessions.getClassMetadata( clazz ); + assertTrue( "Entity is annotated with @Timestamp and should hence be versioned", meta.isVersioned() ); + + PersistentClass persistentClass = cfg.getClassMapping( clazz.getName() ); + assertNotNull( persistentClass ); + Property versionProperty = persistentClass.getVersion(); + assertNotNull( versionProperty ); + assertEquals( "Wrong timestamp type", expectedTypeClass, versionProperty.getType().getClass() ); + } + + protected Class[] getAnnotatedClasses() { + return new Class[] { + VMTimestamped.class, DBTimestamped.class + }; + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/annotations/various/VMTimestamped.java b/testsuite/src/test/java/org/hibernate/test/annotations/various/VMTimestamped.java new file mode 100644 index 0000000000..0de8daae02 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/annotations/various/VMTimestamped.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +// $Id:$ +package org.hibernate.test.annotations.various; + +import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Version; + +import org.hibernate.annotations.Source; + +/** + * @author Hardy Ferentschik + */ +@Entity +public class VMTimestamped { + @Id + @GeneratedValue + private int id; + + @Version + @Source + private Date lastUpdate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } +} + +