HHH-4439 - Patch and test
This commit is contained in:
parent
9a7924d9bc
commit
a49e02b239
|
@ -292,8 +292,10 @@
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you'd like to override auditing behaviour of some fields/properties in an embedded component, you can use
|
If you'd like to override auditing behaviour of some fields/properties inherited from
|
||||||
the <literal>@AuditOverride(s)</literal> annotation on the usage site of the component.
|
<interfacename>@Mappedsuperclass</interfacename> or in an embedded component, you can
|
||||||
|
apply the <literal>@AuditOverride(s)</literal> annotation on the subtype or usage site
|
||||||
|
of the component.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.hibernate.envers;
|
package org.hibernate.envers;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
@ -9,9 +10,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code AuditingOverride} annotation is used to override the auditing
|
* The {@code AuditingOverride} annotation is used to override the auditing
|
||||||
* behavior of a field (or property) inside an embedded component.
|
* behavior of a field (or property) inherited from {@link MappedSuperclass}
|
||||||
|
* type or inside an embedded component.
|
||||||
*
|
*
|
||||||
* @author Erik-Berndt Scheper
|
* @author Erik-Berndt Scheper
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
* @see javax.persistence.Embedded
|
* @see javax.persistence.Embedded
|
||||||
* @see javax.persistence.Embeddable
|
* @see javax.persistence.Embeddable
|
||||||
* @see javax.persistence.MappedSuperclass
|
* @see javax.persistence.MappedSuperclass
|
||||||
|
@ -38,4 +41,11 @@ public @interface AuditOverride {
|
||||||
* is ignored if {@link #isAudited()} equals to {@code false}.
|
* is ignored if {@link #isAudited()} equals to {@code false}.
|
||||||
*/
|
*/
|
||||||
AuditJoinTable auditJoinTable() default @AuditJoinTable;
|
AuditJoinTable auditJoinTable() default @AuditJoinTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Specifies class which field (or property) mapping is being overridden. <strong>Required</strong> if
|
||||||
|
* {@link AuditOverride} is used to change auditing behavior of attributes inherited from {@link MappedSuperclass}
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
Class relatedClass() default void.class;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public @interface Audited {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when
|
* @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when
|
||||||
* reading a historic version an audited entity, the realtion will always point to the "current" entity.
|
* reading a historic version an audited entity, the relation will always point to the "current" entity.
|
||||||
* This is useful for dictionary-like entities, which don't change and don't need to be audited.
|
* This is useful for dictionary-like entities, which don't change and don't need to be audited.
|
||||||
*/
|
*/
|
||||||
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
|
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.hibernate.envers.configuration.metadata.reader;
|
package org.hibernate.envers.configuration.metadata.reader;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -20,8 +22,10 @@ import org.hibernate.envers.AuditOverrides;
|
||||||
import org.hibernate.envers.Audited;
|
import org.hibernate.envers.Audited;
|
||||||
import org.hibernate.envers.ModificationStore;
|
import org.hibernate.envers.ModificationStore;
|
||||||
import org.hibernate.envers.NotAudited;
|
import org.hibernate.envers.NotAudited;
|
||||||
|
import org.hibernate.envers.RelationTargetAuditMode;
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.tools.MappingTools;
|
import org.hibernate.envers.tools.MappingTools;
|
||||||
|
import org.hibernate.envers.tools.Tools;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
|
@ -53,6 +57,9 @@ public class AuditedPropertiesReader {
|
||||||
// Mapping class field to corresponding <properties> element.
|
// Mapping class field to corresponding <properties> element.
|
||||||
private final Map<String, String> propertiesGroupMapping;
|
private final Map<String, String> propertiesGroupMapping;
|
||||||
|
|
||||||
|
private final Set<XProperty> overriddenAuditedProperties;
|
||||||
|
private final Set<XProperty> overriddenNotAuditedProperties;
|
||||||
|
|
||||||
public AuditedPropertiesReader(ModificationStore defaultStore,
|
public AuditedPropertiesReader(ModificationStore defaultStore,
|
||||||
PersistentPropertiesSource persistentPropertiesSource,
|
PersistentPropertiesSource persistentPropertiesSource,
|
||||||
AuditedPropertiesHolder auditedPropertiesHolder,
|
AuditedPropertiesHolder auditedPropertiesHolder,
|
||||||
|
@ -69,6 +76,9 @@ public class AuditedPropertiesReader {
|
||||||
propertyAccessedPersistentProperties = newHashSet();
|
propertyAccessedPersistentProperties = newHashSet();
|
||||||
fieldAccessedPersistentProperties = newHashSet();
|
fieldAccessedPersistentProperties = newHashSet();
|
||||||
propertiesGroupMapping = newHashMap();
|
propertiesGroupMapping = newHashMap();
|
||||||
|
|
||||||
|
overriddenAuditedProperties = newHashSet();
|
||||||
|
overriddenNotAuditedProperties = newHashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read() {
|
public void read() {
|
||||||
|
@ -80,11 +90,64 @@ public class AuditedPropertiesReader {
|
||||||
XClass clazz = persistentPropertiesSource.getXClass();
|
XClass clazz = persistentPropertiesSource.getXClass();
|
||||||
Set<XClass> declaredAuditedSuperclasses = new HashSet<XClass>();
|
Set<XClass> declaredAuditedSuperclasses = new HashSet<XClass>();
|
||||||
doGetDeclaredAuditedSuperclasses(clazz, declaredAuditedSuperclasses);
|
doGetDeclaredAuditedSuperclasses(clazz, declaredAuditedSuperclasses);
|
||||||
|
doReadOverrideAuditedProperties(clazz);
|
||||||
|
|
||||||
// Adding all properties from the given class.
|
// Adding all properties from the given class.
|
||||||
addPropertiesFromClass(clazz, declaredAuditedSuperclasses);
|
addPropertiesFromClass(clazz, declaredAuditedSuperclasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively constructs sets of audited and not audited properties which behavior has been overridden
|
||||||
|
* using @AuditOverride annotation.
|
||||||
|
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
||||||
|
*/
|
||||||
|
private void doReadOverrideAuditedProperties(XClass clazz) {
|
||||||
|
List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
|
||||||
|
for (AuditOverride auditOverride : auditOverrides) {
|
||||||
|
if (auditOverride.relatedClass() != void.class) {
|
||||||
|
XClass overrideClass = reflectionManager.toXClass(auditOverride.relatedClass());
|
||||||
|
checkSuperclass(clazz, overrideClass);
|
||||||
|
String propertyName = auditOverride.name();
|
||||||
|
if (propertyName != null) {
|
||||||
|
XProperty property = getProperty(overrideClass, propertyName);
|
||||||
|
if (auditOverride.isAudited()) {
|
||||||
|
if (!overriddenNotAuditedProperties.contains(property)) {
|
||||||
|
// If the property has not been marked as not audited by the subclass.
|
||||||
|
overriddenAuditedProperties.add(property);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!overriddenAuditedProperties.contains(property)) {
|
||||||
|
// If the property has not been marked as audited by the subclass.
|
||||||
|
overriddenNotAuditedProperties.add(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XClass superclass = clazz.getSuperclass();
|
||||||
|
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
|
||||||
|
doReadOverrideAuditedProperties(superclass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz Source class.
|
||||||
|
* @return List of @AuditOverride annotations applied at class level.
|
||||||
|
*/
|
||||||
|
private List<AuditOverride> computeAuditOverrides(XClass clazz) {
|
||||||
|
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class);
|
||||||
|
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class);
|
||||||
|
if (auditOverrides == null && auditOverride != null) {
|
||||||
|
return Arrays.asList(auditOverride);
|
||||||
|
} else if (auditOverrides != null && auditOverride == null) {
|
||||||
|
return Arrays.asList(auditOverrides.value());
|
||||||
|
} else if (auditOverrides != null && auditOverride != null) {
|
||||||
|
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
|
||||||
|
"Please revise Envers annotations applied to class " + clazz.getName() + ".");
|
||||||
|
}
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively constructs a set of classes that have been declared for auditing process.
|
* Recursively constructs a set of classes that have been declared for auditing process.
|
||||||
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
|
||||||
|
@ -115,10 +178,25 @@ public class AuditedPropertiesReader {
|
||||||
private void checkSuperclass(XClass child, XClass parent) {
|
private void checkSuperclass(XClass child, XClass parent) {
|
||||||
if (!parent.isAssignableFrom(child)) {
|
if (!parent.isAssignableFrom(child)) {
|
||||||
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
|
||||||
"Please revise @Audited.auditParents value in " + child.getName() + " type.");
|
"Please revise Envers annotations applied to " + child.getName() + " type.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
|
||||||
|
* @param clazz Class.
|
||||||
|
* @param propertyName Property name.
|
||||||
|
* @return Property object.
|
||||||
|
*/
|
||||||
|
private XProperty getProperty(XClass clazz, String propertyName) {
|
||||||
|
XProperty property = Tools.getProperty(clazz, propertyName);
|
||||||
|
if (property == null) {
|
||||||
|
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
|
||||||
|
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + ".");
|
||||||
|
}
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
private void readPersistentPropertiesAccess() {
|
private void readPersistentPropertiesAccess() {
|
||||||
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
|
||||||
while (propertyIter.hasNext()) {
|
while (propertyIter.hasNext()) {
|
||||||
|
@ -283,7 +361,7 @@ public class AuditedPropertiesReader {
|
||||||
// check if a property is declared as not audited to exclude it
|
// check if a property is declared as not audited to exclude it
|
||||||
// useful if a class is audited but some properties should be excluded
|
// useful if a class is audited but some properties should be excluded
|
||||||
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
NotAudited unVer = property.getAnnotation(NotAudited.class);
|
||||||
if (unVer != null) {
|
if ((unVer != null && !overriddenAuditedProperties.contains(property)) || overriddenNotAuditedProperties.contains(property)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// if the optimistic locking field has to be unversioned and the current property
|
// if the optimistic locking field has to be unversioned and the current property
|
||||||
|
@ -327,11 +405,29 @@ public class AuditedPropertiesReader {
|
||||||
propertyData.setStore(aud.modStore());
|
propertyData.setStore(aud.modStore());
|
||||||
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
|
||||||
return true;
|
return true;
|
||||||
|
} else if (overriddenAuditedProperties.contains(property)) {
|
||||||
|
// Filling property data with @Audited defaults. If anyone needs to customize those values in the future,
|
||||||
|
// appropriate fields shall be added to @AuditOverride annotation.
|
||||||
|
fillAuditedDefaults(propertyData);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills given property data with default values of @Audited.modStore and @Audited.targetAuditMode attributes.
|
||||||
|
* @param propertyData Property data.
|
||||||
|
*/
|
||||||
|
private void fillAuditedDefaults(PropertyAuditingData propertyData) {
|
||||||
|
try {
|
||||||
|
propertyData.setStore((ModificationStore) Audited.class.getMethod("modStore").getDefaultValue());
|
||||||
|
propertyData.setRelationTargetAuditMode((RelationTargetAuditMode) Audited.class.getMethod("targetAuditMode").getDefaultValue());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
|
||||||
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
|
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
|
||||||
if (auditMappedBy != null) {
|
if (auditMappedBy != null) {
|
||||||
|
|
|
@ -35,6 +35,8 @@ import java.util.Set;
|
||||||
import javassist.util.proxy.ProxyFactory;
|
import javassist.util.proxy.ProxyFactory;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -215,4 +217,32 @@ public class Tools {
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz Source class.
|
||||||
|
* @param propertyName Property name.
|
||||||
|
* @return Property object or {@code null} if one with expected name has not been found.
|
||||||
|
*/
|
||||||
|
public static XProperty getProperty(XClass clazz, String propertyName) {
|
||||||
|
XProperty property = getProperty(clazz, propertyName, "field");
|
||||||
|
if (property == null) {
|
||||||
|
property = getProperty(clazz, propertyName, "property");
|
||||||
|
}
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz Source class.
|
||||||
|
* @param propertyName Property name.
|
||||||
|
* @param accessType Expected access type. Legal values are <i>field</i> and <i>property</i>.
|
||||||
|
* @return Property object or {@code null} if one with expected name and access type has not been found.
|
||||||
|
*/
|
||||||
|
public static XProperty getProperty(XClass clazz, String propertyName, String accessType) {
|
||||||
|
for (XProperty property : clazz.getDeclaredProperties(accessType)) {
|
||||||
|
if (propertyName.equals(property.getName())) {
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.Priority;
|
||||||
|
import org.hibernate.mapping.Column;
|
||||||
|
import org.hibernate.mapping.Table;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-4439")
|
||||||
|
public class AuditOverrideTest extends AbstractEntityTest {
|
||||||
|
private Integer propertyEntityId = null;
|
||||||
|
private Integer transitiveEntityId = null;
|
||||||
|
private Integer auditedEntityId = null;
|
||||||
|
private Table propertyTable = null;
|
||||||
|
private Table transitiveTable = null;
|
||||||
|
private Table auditedTable = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(PropertyOverrideTestEntity.class);
|
||||||
|
cfg.addAnnotatedClass(TransitiveOverrideTestEntity.class);
|
||||||
|
cfg.addAnnotatedClass(AuditedSpecialEntity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
|
||||||
|
// Revision 1
|
||||||
|
em.getTransaction().begin();
|
||||||
|
PropertyOverrideTestEntity propertyEntity = new PropertyOverrideTestEntity("data 1", 1, "data 2");
|
||||||
|
em.persist(propertyEntity);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
propertyEntityId = propertyEntity.getId();
|
||||||
|
|
||||||
|
// Revision 2
|
||||||
|
em.getTransaction().begin();
|
||||||
|
TransitiveOverrideTestEntity transitiveEntity = new TransitiveOverrideTestEntity("data 1", 1, "data 2", 2, "data 3");
|
||||||
|
em.persist(transitiveEntity);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
transitiveEntityId = transitiveEntity.getId();
|
||||||
|
|
||||||
|
// Revision 3
|
||||||
|
em.getTransaction().begin();
|
||||||
|
AuditedSpecialEntity auditedEntity = new AuditedSpecialEntity("data 1", 1, "data 2");
|
||||||
|
em.persist(auditedEntity);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
auditedEntityId = auditedEntity.getId();
|
||||||
|
|
||||||
|
propertyTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditoverride.PropertyOverrideTestEntity_AUD").getTable();
|
||||||
|
transitiveTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditoverride.TransitiveOverrideTestEntity_AUD").getTable();
|
||||||
|
auditedTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditoverride.AuditedSpecialEntity_AUD").getTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotAuditedProperty() {
|
||||||
|
Assert.assertNull(propertyTable.getColumn(new Column("str1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAuditedProperty() {
|
||||||
|
Assert.assertNotNull(propertyTable.getColumn(new Column("number1")));
|
||||||
|
Assert.assertNotNull(transitiveTable.getColumn(new Column("number2")));
|
||||||
|
Assert.assertNotNull(auditedTable.getColumn(new Column("str1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransitiveAuditedProperty() {
|
||||||
|
Assert.assertNotNull(transitiveTable.getColumn(new Column("number1")));
|
||||||
|
Assert.assertNotNull(transitiveTable.getColumn(new Column("str1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHistoryOfPropertyOverrideEntity() {
|
||||||
|
PropertyOverrideTestEntity ver1 = new PropertyOverrideTestEntity(null, 1, propertyEntityId, "data 2");
|
||||||
|
Assert.assertEquals(ver1, getAuditReader().find(PropertyOverrideTestEntity.class, propertyEntityId, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHistoryOfTransitiveOverrideEntity() {
|
||||||
|
TransitiveOverrideTestEntity ver1 = new TransitiveOverrideTestEntity("data 1", 1, transitiveEntityId, "data 2", 2, "data 3");
|
||||||
|
Assert.assertEquals(ver1, getAuditReader().find(TransitiveOverrideTestEntity.class, transitiveEntityId, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHistoryOfAuditedSpecialEntity() {
|
||||||
|
AuditedSpecialEntity ver1 = new AuditedSpecialEntity("data 1", null, auditedEntityId, "data 2");
|
||||||
|
Assert.assertEquals(ver1, getAuditReader().find(AuditedSpecialEntity.class, auditedEntityId, 3));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.envers.AuditOverride;
|
||||||
|
import org.hibernate.envers.AuditOverrides;
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@AuditOverrides({@AuditOverride(relatedClass = NotAnnotatedBaseEntity.class, name = "str1", isAudited = true)})
|
||||||
|
public class AuditedSpecialEntity extends NotAnnotatedBaseEntity {
|
||||||
|
@Audited
|
||||||
|
private String str2;
|
||||||
|
|
||||||
|
public AuditedSpecialEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuditedSpecialEntity(String str1, Integer number, String str2) {
|
||||||
|
super(str1, number);
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuditedSpecialEntity(String str1, Integer number, Integer id, String str2) {
|
||||||
|
super(str1, number, id);
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof AuditedSpecialEntity)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
|
||||||
|
AuditedSpecialEntity that = (AuditedSpecialEntity) o;
|
||||||
|
|
||||||
|
if (str2 != null ? !str2.equals(that.str2) : that.str2 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (str2 != null ? str2.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AuditedSpecialEntity(" + super.toString() + ", str2 = " + str2 + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr2() {
|
||||||
|
return str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr2(String str2) {
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.NotAudited;
|
||||||
|
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
public class BaseEntity implements Serializable {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Audited
|
||||||
|
private String str1;
|
||||||
|
|
||||||
|
@NotAudited
|
||||||
|
private Integer number1;
|
||||||
|
|
||||||
|
public BaseEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseEntity(String str1, Integer number1, Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
this.str1 = str1;
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseEntity(String str1, Integer number1) {
|
||||||
|
this.str1 = str1;
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr1() {
|
||||||
|
return str1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr1(String str1) {
|
||||||
|
this.str1 = str1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNumber1() {
|
||||||
|
return number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber1(Integer number1) {
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof BaseEntity)) return false;
|
||||||
|
|
||||||
|
BaseEntity that = (BaseEntity) o;
|
||||||
|
|
||||||
|
if (id != null ? !id.equals(that.id) : that.id != null) return false;
|
||||||
|
if (number1 != null ? !number1.equals(that.number1) : that.number1 != null) return false;
|
||||||
|
if (str1 != null ? !str1.equals(that.str1) : that.str1 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result;
|
||||||
|
result = (id != null ? id.hashCode() : 0);
|
||||||
|
result = 31 * result + (str1 != null ? str1.hashCode() : 0);
|
||||||
|
result = 31 * result + (number1 != null ? number1.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "BaseEntity(id = " + id + ", str1 = " + str1 + ", number1 = " + number1 + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.envers.AuditOverride;
|
||||||
|
import org.hibernate.envers.AuditOverrides;
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.NotAudited;
|
||||||
|
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
@AuditOverrides({@AuditOverride(relatedClass = BaseEntity.class, name = "str1", isAudited = false),
|
||||||
|
@AuditOverride(relatedClass = BaseEntity.class, name = "number1", isAudited = true)})
|
||||||
|
public class ExtendedBaseEntity extends BaseEntity {
|
||||||
|
@Audited
|
||||||
|
private String str2;
|
||||||
|
|
||||||
|
@NotAudited
|
||||||
|
private Integer number2;
|
||||||
|
|
||||||
|
public ExtendedBaseEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtendedBaseEntity(String str1, Integer number1, Integer id, String str2, Integer number2) {
|
||||||
|
super(str1, number1, id);
|
||||||
|
this.str2 = str2;
|
||||||
|
this.number2 = number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtendedBaseEntity(String str1, Integer number1, String str2, Integer number2) {
|
||||||
|
super(str1, number1);
|
||||||
|
this.str2 = str2;
|
||||||
|
this.number2 = number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof ExtendedBaseEntity)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
|
||||||
|
ExtendedBaseEntity that = (ExtendedBaseEntity) o;
|
||||||
|
|
||||||
|
if (number2 != null ? !number2.equals(that.number2) : that.number2 != null) return false;
|
||||||
|
if (str2 != null ? !str2.equals(that.str2) : that.str2 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (str2 != null ? str2.hashCode() : 0);
|
||||||
|
result = 31 * result + (number2 != null ? number2.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ExtendedBaseEntity(" + super.toString() + ", str2 = " + str2 + ", number2 = " + number2 + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr2() {
|
||||||
|
return str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr2(String str2) {
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNumber2() {
|
||||||
|
return number2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber2(Integer number2) {
|
||||||
|
this.number2 = number2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
public class NotAnnotatedBaseEntity implements Serializable {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String str1;
|
||||||
|
|
||||||
|
private Integer number1;
|
||||||
|
|
||||||
|
public NotAnnotatedBaseEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotAnnotatedBaseEntity(String str1, Integer number1, Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
this.str1 = str1;
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotAnnotatedBaseEntity(String str1, Integer number1) {
|
||||||
|
this.str1 = str1;
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr1() {
|
||||||
|
return str1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr1(String str1) {
|
||||||
|
this.str1 = str1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getNumber1() {
|
||||||
|
return number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber1(Integer number1) {
|
||||||
|
this.number1 = number1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof NotAnnotatedBaseEntity)) return false;
|
||||||
|
|
||||||
|
NotAnnotatedBaseEntity that = (NotAnnotatedBaseEntity) o;
|
||||||
|
|
||||||
|
if (id != null ? !id.equals(that.id) : that.id != null) return false;
|
||||||
|
if (number1 != null ? !number1.equals(that.number1) : that.number1 != null) return false;
|
||||||
|
if (str1 != null ? !str1.equals(that.str1) : that.str1 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result;
|
||||||
|
result = (id != null ? id.hashCode() : 0);
|
||||||
|
result = 31 * result + (str1 != null ? str1.hashCode() : 0);
|
||||||
|
result = 31 * result + (number1 != null ? number1.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "NotAnnotatedBaseEntity(id = " + id + ", str1 = " + str1 + ", number1 = " + number1 + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.envers.AuditOverride;
|
||||||
|
import org.hibernate.envers.AuditOverrides;
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
@AuditOverrides({@AuditOverride(relatedClass = BaseEntity.class, name = "str1", isAudited = false),
|
||||||
|
@AuditOverride(relatedClass = BaseEntity.class, name = "number1", isAudited = true)})
|
||||||
|
public class PropertyOverrideTestEntity extends BaseEntity {
|
||||||
|
private String str2;
|
||||||
|
|
||||||
|
public PropertyOverrideTestEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyOverrideTestEntity(String str1, Integer number1, String str2) {
|
||||||
|
super(str1, number1);
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyOverrideTestEntity(String str1, Integer number1, Integer id, String str2) {
|
||||||
|
super(str1, number1, id);
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof PropertyOverrideTestEntity)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
|
||||||
|
PropertyOverrideTestEntity that = (PropertyOverrideTestEntity) o;
|
||||||
|
|
||||||
|
if (str2 != null ? !str2.equals(that.str2) : that.str2 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (str2 != null ? str2.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PropertyOverrideTestEntity(" + super.toString() + ", str2 = " + str2 + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr2() {
|
||||||
|
return str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr2(String str2) {
|
||||||
|
this.str2 = str2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.hibernate.envers.test.integration.superclass.auditoverride;
|
||||||
|
|
||||||
|
import org.hibernate.envers.AuditOverride;
|
||||||
|
import org.hibernate.envers.AuditOverrides;
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
@AuditOverrides({@AuditOverride(relatedClass = BaseEntity.class, name = "str1", isAudited = true),
|
||||||
|
@AuditOverride(relatedClass = ExtendedBaseEntity.class, name = "number2", isAudited = true)})
|
||||||
|
public class TransitiveOverrideTestEntity extends ExtendedBaseEntity {
|
||||||
|
private String str3;
|
||||||
|
|
||||||
|
public TransitiveOverrideTestEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransitiveOverrideTestEntity(String str1, Integer number1, Integer id, String str2, Integer number2, String str3) {
|
||||||
|
super(str1, number1, id, str2, number2);
|
||||||
|
this.str3 = str3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransitiveOverrideTestEntity(String str1, Integer number1, String str2, Integer number2, String str3) {
|
||||||
|
super(str1, number1, str2, number2);
|
||||||
|
this.str3 = str3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof TransitiveOverrideTestEntity)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
|
||||||
|
TransitiveOverrideTestEntity that = (TransitiveOverrideTestEntity) o;
|
||||||
|
|
||||||
|
if (str3 != null ? !str3.equals(that.str3) : that.str3 != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (str3 != null ? str3.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TransitiveOverrideTestEntity(" + super.toString() + ", str3 = " + str3 + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStr3() {
|
||||||
|
return str3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr3(String str3) {
|
||||||
|
this.str3 = str3;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue