HHH-6210 Added config option to allow revend timestamp fields to be long data types

This commit is contained in:
Chris Cranford 2021-11-26 00:49:33 -05:00
parent 1abf044f2e
commit 205f0ce9bf
6 changed files with 166 additions and 5 deletions

View File

@ -257,6 +257,10 @@ This property is only evaluated if the `ValidityAuditStrategy` is used.
Column name of the timestamp of the end revision until which the data was valid.
Only used if the `ValidityAuditStrategy` is used, and `org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` evaluates to true.
`*org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric*`(default: `false` )::
Boolean flag that controls whether the revision end timestamp field is treated as a `Long` data type.
Only used if the `ValidityAuditStrategy` is used, and `org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` evaluates to true.
`*org.hibernate.envers.use_revision_entity_with_native_id*` (default: `true` )::
Boolean flag that determines the strategy of revision number generation.
Default implementation of revision entity uses native identifier generator.
@ -320,6 +324,7 @@ The following configuration options have been added recently and should be regar
. `org.hibernate.envers.modified_column_naming_strategy`
. `org.hibernate.envers.original_id_prop_name`
. `org.hibernate.envers.find_by_revision_exact_match`
. `org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric`
====
[[envers-additional-mappings]]
@ -1489,6 +1494,8 @@ Optionally, you can also override the default values using following properties:
`org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name`
`org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric`
For more information, see <<envers-configuration>>.
====

View File

@ -90,6 +90,7 @@ public class Configuration {
private final String revisionEndTimestampFieldName;
private final String embeddableSetOrdinalPropertyName;
private final boolean revisionEndTimestampEnabled;
private final boolean revisionEndTimestampNumeric;
private final Map<String, String> customAuditTableNames = new HashMap<>();
@ -152,9 +153,14 @@ public class Configuration {
EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME,
DEFAULT_REV_TSTMP_FIELD
);
revisionEndTimestampNumeric = configProps.getBoolean(
EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_NUMERIC,
false
);
}
else {
revisionEndTimestampFieldName = null;
revisionEndTimestampNumeric = false;
}
embeddableSetOrdinalPropertyName = configProps.getString(
@ -219,6 +225,10 @@ public class Configuration {
return revisionEndTimestampEnabled;
}
public boolean isRevisionEndTimestampNumeric() {
return revisionEndTimestampNumeric;
}
public String getDefaultCatalogName() {
return defaultCatalogName;
}

View File

@ -110,6 +110,14 @@ public interface EnversSettings {
*/
String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_FIELD_NAME = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name";
/**
* Determines whether the timestamp of the end revision is stored as a numeric data type.
* Defaults to {@literal false}.
*
* @since 6.0
*/
String AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_NUMERIC = "org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric";
/**
* Name of column used for storing ordinal of the change in sets of embeddable elements. Defaults to {@literal SETORDINAL}.
*/

View File

@ -109,7 +109,13 @@ public class ValidityAuditStrategy implements AuditStrategy {
if ( mappingContext.getConfiguration().isRevisionEndTimestampEnabled() ) {
// add a column for the timestamp of the end revision
final String revisionInfoTimestampTypeName = StandardBasicTypes.TIMESTAMP.getName();
final String revisionInfoTimestampTypeName;
if ( mappingContext.getConfiguration().isRevisionEndTimestampNumeric() ) {
revisionInfoTimestampTypeName = StandardBasicTypes.LONG.getName();
}
else {
revisionInfoTimestampTypeName = StandardBasicTypes.TIMESTAMP.getName();
}
final BasicAttribute revEndTimestampMapping = new BasicAttribute(
mappingContext.getConfiguration().getRevisionEndTimestampFieldName(),
revisionInfoTimestampTypeName,
@ -225,13 +231,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
// set [, REVEND_TSTMP = ?]
if ( isRevisionEndTimestampEnabled ) {
final Object revEndTimestampObj = revisionTimestampGetter.get( revision );
final Date revisionEndTimestamp = convertRevEndTimestampToDate( revEndTimestampObj );
final Object revEndValue = getRevEndTimestampValue( configuration, revEndTimestampObj );
final Type revEndTsType = rootAuditedEntityQueryable.getPropertyType(
configuration.getRevisionEndTimestampFieldName()
);
revEndTsType.nullSafeSet(
preparedStatement, revisionEndTimestamp, index, sessionImplementor
);
revEndTsType.nullSafeSet( preparedStatement, revEndValue, index, sessionImplementor );
index += revEndTsType.getColumnSpan( sessionImplementor.getFactory() );
}
@ -445,6 +449,20 @@ public class ValidityAuditStrategy implements AuditStrategy {
return new Date( (Long) revEndTimestampObj );
}
private Long convertRevEndTimestampToLong(Object revEndTimstampObj) {
if ( revEndTimstampObj instanceof Date ) {
return ( (Date) revEndTimstampObj ).getTime();
}
return (Long) revEndTimstampObj;
}
private Object getRevEndTimestampValue(Configuration configuration, Object value) {
if ( configuration.isRevisionEndTimestampNumeric() ) {
return convertRevEndTimestampToLong( value );
}
return convertRevEndTimestampToDate( value );
}
private Queryable getQueryable(String entityName, SessionImplementor sessionImplementor) {
return (Queryable) sessionImplementor.getFactory().getMetamodel().entityPersister( entityName );
}

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.strategy;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.envers.strategy.internal.ValidityAuditStrategy;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.entities.StrTestEntity;
import org.hibernate.type.BasicType;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.envers.RequiresAuditStrategy;
/**
* Tests the {@code REVEND} functionality using a {@code LONG} data type.
* This is only applicable with the ValidityAuditStrategy.
*
* @author Chris Cranford
*/
@TestForIssue( jiraKey = "HHH-6210" )
@RequiresAuditStrategy( value = ValidityAuditStrategy.class, jiraKey = "HHH-6210" )
public class RevisionEndNumericTypeTest extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { StrTestEntity.class };
}
@Override
protected void addConfigOptions(Map options) {
super.addConfigOptions( options );
options.put( EnversSettings.AUDIT_STRATEGY_VALIDITY_STORE_REVEND_TIMESTAMP, "true" );
options.put( EnversSettings.AUDIT_STRATEGY_VALIDITY_REVEND_TIMESTAMP_NUMERIC, "true" );
}
@Test
public void testRevisionEndTimestampIsTimestampType() {
// get the entity and verify the revision end timestamp property exists
final PersistentClass clazz = metadata().getEntityBinding( StrTestEntity.class.getName() + "_AUD" );
assertTrue( clazz.hasProperty( "REVEND_TSTMP" ) );
final Property property = clazz.getProperty( "REVEND_TSTMP" );
assertTyping( BasicType.class, clazz.getProperty( "REVEND_TSTMP" ).getType() );
assertEquals( Long.class, ( (BasicType) property.getType() ).getJavaType() );
}
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.strategy;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.junit.Assert.assertEquals;
import java.sql.Timestamp;
import java.util.Map;
import org.hibernate.envers.configuration.EnversSettings;
import org.hibernate.envers.strategy.internal.ValidityAuditStrategy;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.entities.StrTestEntity;
import org.hibernate.type.BasicType;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.envers.RequiresAuditStrategy;
/**
* Tests the {@code REVEND} functionality using a {@code LONG} data type.
* This is only applicable with the ValidityAuditStrategy.
*
* @author Chris Cranford
*/
@TestForIssue( jiraKey = "HHH-6210" )
@RequiresAuditStrategy( value = ValidityAuditStrategy.class, jiraKey = "HHH-6210" )
public class RevisionEndTimestampTypeTest extends BaseEnversJPAFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { StrTestEntity.class };
}
@Override
protected void addConfigOptions(Map options) {
options.put( EnversSettings.AUDIT_STRATEGY_VALIDITY_STORE_REVEND_TIMESTAMP, "true" );
}
@Test
public void testRevisionEndTimestampIsLongType() {
// get the entity and verify the revision end timestamp property exists
final PersistentClass clazz = metadata().getEntityBinding( StrTestEntity.class.getName() + "_AUD" );
final Property property = clazz.getProperty( "REVEND_TSTMP" );
assertTyping( BasicType.class, property.getType() );
assertEquals( Timestamp.class, ( (BasicType) property.getType() ).getJavaType() );
}
}