HHH-8769 gracefully handle the lack of dynamic mode support in Envers

This commit is contained in:
Brett Meyer 2015-03-22 00:49:08 -04:00
parent a05460a23f
commit b70bc0080e
3 changed files with 87 additions and 86 deletions

View File

@ -23,10 +23,9 @@
*/
package org.hibernate.envers.configuration.internal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.spi.MetadataImplementor;
@ -42,9 +41,9 @@ import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.ServiceRegistry;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
@ -74,12 +73,15 @@ public class EntitiesConfigurator {
while ( classes.hasNext() ) {
final PersistentClass pc = classes.next();
// Collecting information from annotations on the persistent class pc
final AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader( globalConfiguration, reflectionManager, pc );
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
// Ensure we're in POJO, not dynamic model, mapping.
if (pc.getClassName() != null) {
// Collecting information from annotations on the persistent class pc
final AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader(globalConfiguration, reflectionManager, pc);
final ClassAuditingData auditData = annotationsMetadataReader.getAuditData();
classesAuditingData.addClassAuditingData( pc, auditData );
classesAuditingData.addClassAuditingData(pc, auditData);
}
}
// Now that all information is read we can update the calculated fields.

View File

@ -23,10 +23,8 @@
*/
package org.hibernate.envers.configuration.internal;
import java.util.Date;
import java.util.Set;
import javax.persistence.Column;
import org.dom4j.Document;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
@ -57,8 +55,9 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.type.LongType;
import org.hibernate.type.Type;
import org.dom4j.Document;
import org.dom4j.Element;
import javax.persistence.Column;
import java.util.Date;
import java.util.Set;
/**
* @author Adam Warski (adam at warski dot org)
@ -316,77 +315,79 @@ public class RevisionInfoConfiguration {
Class<?> revisionInfoClass = null;
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
XClass clazz;
try {
clazz = reflectionManager.classForName( persistentClass.getClassName(), this.getClass() );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
if ( revisionEntity != null ) {
if ( revisionEntityFound ) {
throw new MappingException( "Only one entity may be annotated with @RevisionEntity!" );
// Ensure we're in POJO, not dynamic model, mapping.
if (persistentClass.getClassName() != null) {
XClass clazz;
try {
clazz = reflectionManager.classForName( persistentClass.getClassName(), this.getClass() );
}
catch (ClassNotFoundException e) {
throw new MappingException( e );
}
// Checking if custom revision entity isn't audited
if ( clazz.getAnnotation( Audited.class ) != null ) {
throw new MappingException( "An entity annotated with @RevisionEntity cannot be audited!" );
}
final RevisionEntity revisionEntity = clazz.getAnnotation( RevisionEntity.class );
if ( revisionEntity != null ) {
if (revisionEntityFound) {
throw new MappingException("Only one entity may be annotated with @RevisionEntity!");
}
revisionEntityFound = true;
// Checking if custom revision entity isn't audited
if (clazz.getAnnotation(Audited.class) != null) {
throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!");
}
final MutableBoolean revisionNumberFound = new MutableBoolean();
final MutableBoolean revisionTimestampFound = new MutableBoolean();
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
revisionEntityFound = true;
searchForRevisionInfoCfg(
clazz,
reflectionManager,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
);
final MutableBoolean revisionNumberFound = new MutableBoolean();
final MutableBoolean revisionTimestampFound = new MutableBoolean();
final MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
if ( !revisionNumberFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionNumber!"
searchForRevisionInfoCfg(
clazz,
reflectionManager,
revisionNumberFound,
revisionTimestampFound,
modifiedEntityNamesFound
);
}
if ( !revisionTimestampFound.isSet() ) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionTimestamp!"
);
}
if (!revisionNumberFound.isSet()) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionNumber!"
);
}
revisionInfoEntityName = persistentClass.getEntityName();
revisionInfoClass = persistentClass.getMappedClass();
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass( revisionEntity.value() );
revisionInfoTimestampType = persistentClass.getProperty( revisionInfoTimestampData.getName() ).getType();
if ( globalCfg.isTrackEntitiesChangedInRevision()
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom( revisionInfoClass ))
|| modifiedEntityNamesFound.isSet() ) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision( true );
}
else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
if (!revisionTimestampFound.isSet()) {
throw new MappingException(
"An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionTimestamp!"
);
}
revisionInfoEntityName = persistentClass.getEntityName();
revisionInfoClass = persistentClass.getMappedClass();
final Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
revisionInfoTimestampType = persistentClass.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevision()
|| (globalCfg.isUseRevisionEntityWithNativeId() && DefaultTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom(revisionInfoClass))
|| (!globalCfg.isUseRevisionEntityWithNativeId() && SequenceIdTrackingModifiedEntitiesRevisionEntity.class
.isAssignableFrom(revisionInfoClass))
|| modifiedEntityNamesFound.isSet()) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(
revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData
);
globalCfg.setTrackEntitiesChangedInRevision(true);
} else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(
revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()
);
}
}
}
}

View File

@ -1,13 +1,12 @@
package org.hibernate.envers.test.integration.dynamicmodel;
import static org.junit.Assert.assertNotNull;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import javax.persistence.EntityManager;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
/**
* @author Felix Feisst (feisst dot felix at gmail dot com)
@ -24,7 +23,6 @@ public class DynamicModelTest extends BaseEnversJPAFunctionalTestCase {
* Tests that an EntityManager can be created when using a dynamic model mapping.
*/
@Test
@FailureExpected(jiraKey = "HHH-8769")
public void testDynamicModelMapping() {
EntityManager entityManager = getOrCreateEntityManager();
assertNotNull( "Expected an entity manager to be returned", entityManager );