Merge pull request #112 from lukasz-antoniak/HHH-5917

HHH-5917 - Adding @Audited(auditedParents={classes})
This commit is contained in:
Adam Warski 2011-06-29 09:19:19 -07:00
commit 9129cf38ce
16 changed files with 904 additions and 5 deletions

View File

@ -308,6 +308,14 @@
<literal>@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)</literal>. Then, when reading historic <literal>@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)</literal>. Then, when reading historic
versions of your entity, the relation will always point to the "current" related entity. versions of your entity, the relation will always point to the "current" related entity.
</para> </para>
<para>
If you'd like to audit properties encapsulated by any subset of your entity's mapped superclasses (which are
not explicitly audited), list desired supertypes in <literal>auditParents</literal> attribute of
<interfacename>@Audited</interfacename> annotation. If any <interfacename>@MappedSuperclass</interfacename>
(or any of it's properties) is marked as <interfacename>@Audited</interfacename>, it's behavior is implicitly
inherited by all audited subclasses.
</para>
</section> </section>
<section> <section>

View File

@ -32,6 +32,7 @@ import java.lang.annotation.Target;
* When applied to a field, indicates that this field should be audited. * When applied to a field, indicates that this field should be audited.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Tomasz Bech * @author Tomasz Bech
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@ -44,4 +45,12 @@ public @interface Audited {
* 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;
/**
* @return Set of superclasses which properties shall be audited. The behavior of listed classes
* is the same as if they had {@link Audited} annotation applied on a type level. The scope of this functionality
* is limited to the context of actually mapped entity and its class hierarchy. If a parent type lists any of
* its parent types using this attribute, all fields encapsulated by marked classes are implicitly audited.
*/
Class[] auditParents() default {};
} }

View File

@ -1,6 +1,7 @@
package org.hibernate.envers.configuration.metadata.reader; package org.hibernate.envers.configuration.metadata.reader;
import static org.hibernate.envers.tools.Tools.newHashSet; import static org.hibernate.envers.tools.Tools.newHashSet;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -33,6 +34,7 @@ import org.hibernate.mapping.Value;
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Erik-Berndt Scheper * @author Erik-Berndt Scheper
* @author Hern&aacut;n Chanfreau * @author Hern&aacut;n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class AuditedPropertiesReader { public class AuditedPropertiesReader {
protected final ModificationStore defaultStore; protected final ModificationStore defaultStore;
@ -66,10 +68,50 @@ public class AuditedPropertiesReader {
// First reading the access types for the persistent properties. // First reading the access types for the persistent properties.
readPersistentPropertiesAccess(); readPersistentPropertiesAccess();
// Adding all properties from the given class. // Retrieve classes that are explicitly marked for auditing process by any superclass of currently mapped
addPropertiesFromClass(persistentPropertiesSource.getXClass()); // entity or itself.
XClass clazz = persistentPropertiesSource.getXClass();
Set<XClass> declaredAuditedSuperclasses = new HashSet<XClass>();
doGetDeclaredAuditedSuperclasses(clazz, declaredAuditedSuperclasses);
// Adding all properties from the given class.
addPropertiesFromClass(clazz, declaredAuditedSuperclasses);
} }
/**
* 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 declaredAuditedSuperclasses Total collection of classes listed in {@link Audited#auditParents()} property
* by any superclass starting with class specified as the first argument.
*/
@SuppressWarnings("unchecked")
private void doGetDeclaredAuditedSuperclasses(XClass clazz, Set<XClass> declaredAuditedSuperclasses) {
Audited allClassAudited = clazz.getAnnotation(Audited.class);
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
for (Class c : allClassAudited.auditParents()) {
XClass parentClass = reflectionManager.toXClass(c);
checkSuperclass(clazz, parentClass);
declaredAuditedSuperclasses.add(parentClass);
}
}
XClass superclass = clazz.getSuperclass();
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
doGetDeclaredAuditedSuperclasses(superclass, declaredAuditedSuperclasses);
}
}
/**
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
* @param child Subclass.
* @param parent Superclass.
*/
private void checkSuperclass(XClass child, XClass parent) {
if (!parent.isAssignableFrom(child)) {
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
"Please revise @Audited.auditParents value in " + child.getName() + " type.");
}
}
private void readPersistentPropertiesAccess() { private void readPersistentPropertiesAccess() {
Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator(); Iterator<Property> propertyIter = persistentPropertiesSource.getPropertyIterator();
while (propertyIter.hasNext()) { while (propertyIter.hasNext()) {
@ -82,8 +124,34 @@ public class AuditedPropertiesReader {
} }
} }
private void addPropertiesFromClass(XClass clazz) { /**
Audited allClassAudited = clazz.getAnnotation(Audited.class); * @param clazz Class which properties are currently being added.
* @param declaredAuditedSuperclasses Collection of superclasses that have been explicitly declared to be audited.
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
* checks whether given class exists in collection passed as the second argument. In case of success,
* {@link Audited} configuration of currently mapped entity is returned, otherwise {@code null}.
*/
private Audited computeAuditConfiguration(XClass clazz, Set<XClass> declaredAuditedSuperclasses) {
Audited allClassAudited = clazz.getAnnotation(Audited.class);
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
// forced by any of its child entities configuration (@Audited.auditParents).
if (allClassAudited == null && declaredAuditedSuperclasses.contains(clazz)) {
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
// currently mapped entity.
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class);
}
return allClassAudited;
}
/**
* Recursively adds all audited properties of entity class and its superclasses.
* @param clazz Currently processed class.
* @param declaredAuditedSuperclasses Collection of classes that are declared to be audited
* (see {@link Audited#auditParents()}).
*/
private void addPropertiesFromClass(XClass clazz, Set<XClass> declaredAuditedSuperclasses) {
Audited allClassAudited = computeAuditConfiguration(clazz, declaredAuditedSuperclasses);
//look in the class //look in the class
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited); addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited);
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited); addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited);
@ -91,7 +159,7 @@ public class AuditedPropertiesReader {
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) { if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
XClass superclazz = clazz.getSuperclass(); XClass superclazz = clazz.getSuperclass();
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) { if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
addPropertiesFromClass(superclazz); addPropertiesFromClass(superclazz, declaredAuditedSuperclasses);
} }
} }
} }

View File

@ -0,0 +1,53 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited(auditParents = {MappedParentEntity.class})
public class BabyCompleteEntity extends ChildCompleteEntity {
private String baby;
public BabyCompleteEntity() {
}
public BabyCompleteEntity(Long id, String grandparent, String notAudited, String parent, String child, StrIntTestEntity relation, String baby) {
super(id, grandparent, notAudited, parent, child, relation);
this.baby = baby;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BabyCompleteEntity)) return false;
if (!super.equals(o)) return false;
BabyCompleteEntity that = (BabyCompleteEntity) o;
if (baby != null ? !baby.equals(that.baby) : that.baby != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (baby != null ? baby.hashCode() : 0);
return result;
}
public String toString() {
return "BabyCompleteEntity(" + super.toString() + ", baby = " + baby + ")";
}
public String getBaby() {
return baby;
}
public void setBaby(String baby) {
this.baby = baby;
}
}

View File

@ -0,0 +1,54 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import javax.persistence.MappedSuperclass;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
@Audited(auditParents = {MappedGrandparentEntity.class})
public class ChildCompleteEntity extends MappedParentEntity {
private String child;
public ChildCompleteEntity() {
super(null, null, null, null, null);
}
public ChildCompleteEntity(Long id, String grandparent, String notAudited, String parent, String child, StrIntTestEntity relation) {
super(id, grandparent, notAudited, parent, relation);
this.child = child;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChildCompleteEntity)) return false;
if (!super.equals(o)) return false;
ChildCompleteEntity that = (ChildCompleteEntity) o;
if (child != null ? !child.equals(that.child) : that.child != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (child != null ? child.hashCode() : 0);
return result;
}
public String toString() {
return "ChildCompleteEntity(" + super.toString() + ", child = " + child + ")";
}
public String getChild() {
return child;
}
public void setChild(String child) {
this.child = child;
}
}

View File

@ -0,0 +1,55 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited(auditParents = {MappedParentEntity.class, MappedGrandparentEntity.class})
public class ChildMultipleParentsEntity extends MappedParentEntity {
private String child;
public ChildMultipleParentsEntity() {
super(null, null, null, null, null);
}
public ChildMultipleParentsEntity(Long id, String grandparent, String notAudited, String parent, String child, StrIntTestEntity relation) {
super(id, grandparent, notAudited, parent, relation);
this.child = child;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChildMultipleParentsEntity)) return false;
if (!super.equals(o)) return false;
ChildMultipleParentsEntity that = (ChildMultipleParentsEntity) o;
if (child != null ? !child.equals(that.child) : that.child != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (child != null ? child.hashCode() : 0);
return result;
}
public String toString() {
return "ChildMultipleParentsEntity(" + super.toString() + ", child = " + child + ")";
}
public String getChild() {
return child;
}
public void setChild(String child) {
this.child = child;
}
}

View File

@ -0,0 +1,54 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited(auditParents = {MappedGrandparentEntity.class})
public class ChildSingleParentEntity extends MappedParentEntity {
private String child;
public ChildSingleParentEntity() {
super(null, null, null, null, null);
}
public ChildSingleParentEntity(Long id, String grandparent, String notAudited, String parent, String child, StrIntTestEntity relation) {
super(id, grandparent, notAudited, parent, relation);
this.child = child;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChildSingleParentEntity)) return false;
if (!super.equals(o)) return false;
ChildSingleParentEntity that = (ChildSingleParentEntity) o;
if (child != null ? !child.equals(that.child) : that.child != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (child != null ? child.hashCode() : 0);
return result;
}
public String toString() {
return "ChildSingleParentEntity(" + super.toString() + ", child = " + child + ")";
}
public String getChild() {
return child;
}
public void setChild(String child) {
this.child = child;
}
}

View File

@ -0,0 +1,53 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited(auditParents = {TransitiveParentEntity.class})
public class ExplicitTransitiveChildEntity extends TransitiveParentEntity {
private String child;
public ExplicitTransitiveChildEntity() {
super(null, null, null, null);
}
public ExplicitTransitiveChildEntity(Long id, String grandparent, String notAudited, String parent, String child) {
super(id, grandparent, notAudited, parent);
this.child = child;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ExplicitTransitiveChildEntity)) return false;
if (!super.equals(o)) return false;
ExplicitTransitiveChildEntity that = (ExplicitTransitiveChildEntity) o;
if (child != null ? !child.equals(that.child) : that.child != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (child != null ? child.hashCode() : 0);
return result;
}
public String toString() {
return "ExplicitTransitiveChildEntity(" + super.toString() + ", child = " + child + ")";
}
public String getChild() {
return child;
}
public void setChild(String child) {
this.child = child;
}
}

View File

@ -0,0 +1,53 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@Audited
public class ImplicitTransitiveChildEntity extends TransitiveParentEntity {
private String child;
public ImplicitTransitiveChildEntity() {
super(null, null, null, null);
}
public ImplicitTransitiveChildEntity(Long id, String grandparent, String notAudited, String parent, String child) {
super(id, grandparent, notAudited, parent);
this.child = child;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ImplicitTransitiveChildEntity)) return false;
if (!super.equals(o)) return false;
ImplicitTransitiveChildEntity that = (ImplicitTransitiveChildEntity) o;
if (child != null ? !child.equals(that.child) : that.child != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (child != null ? child.hashCode() : 0);
return result;
}
public String toString() {
return "ImplicitTransitiveChildEntity(" + super.toString() + ", child = " + child + ")";
}
public String getChild() {
return child;
}
public void setChild(String child) {
this.child = child;
}
}

View File

@ -0,0 +1,74 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.NotAudited;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class MappedGrandparentEntity {
@Id
private Long id;
private String grandparent;
@NotAudited
private String notAudited;
public MappedGrandparentEntity(Long id, String grandparent, String notAudited) {
this.id = id;
this.grandparent = grandparent;
this.notAudited = notAudited;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MappedGrandparentEntity)) return false;
MappedGrandparentEntity that = (MappedGrandparentEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (grandparent != null ? !grandparent.equals(that.grandparent) : that.grandparent != null) return false;
if (notAudited != null ? !notAudited.equals(that.notAudited) : that.notAudited != null) return false;
return true;
}
public int hashCode() {
int result = (id != null ? id.hashCode() : 0);
result = 31 * result + (grandparent != null ? grandparent.hashCode() : 0);
result = 31 * result + (notAudited != null ? notAudited.hashCode() : 0);
return result;
}
public String toString() {
return "MappedGrandparentEntity(id = " + id + ", grandparent = " + grandparent + ", notAudited = " + notAudited + ")";
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getGrandparent() {
return grandparent;
}
public void setGrandparent(String grandparent) {
this.grandparent = grandparent;
}
public String getNotAudited() {
return notAudited;
}
public void setNotAudited(String notAudited) {
this.notAudited = notAudited;
}
}

View File

@ -0,0 +1,61 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
public class MappedParentEntity extends MappedGrandparentEntity {
private String parent;
@ManyToOne
private StrIntTestEntity relation;
public MappedParentEntity(Long id, String grandparent, String notAudited, String parent, StrIntTestEntity relation) {
super(id, grandparent, notAudited);
this.parent = parent;
this.relation = relation;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MappedParentEntity)) return false;
if (!super.equals(o)) return false;
MappedParentEntity that = (MappedParentEntity) o;
if (parent != null ? !parent.equals(that.parent) : that.parent != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (parent != null ? parent.hashCode() : 0);
return result;
}
public String toString() {
return "MappedParentEntity(" + super.toString() + ", parent = " + parent + ", relation = " + relation + ")";
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public StrIntTestEntity getRelation() {
return relation;
}
public void setRelation(StrIntTestEntity relation) {
this.relation = relation;
}
}

View File

@ -0,0 +1,73 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.MappedSuperclass;
import java.util.Set;
/**
* Tests mapping of child entity that declares all of its ancestors as audited with {@link Audited#auditParents()} property.
* All supperclasses are marked with {@link MappedSuperclass} annotation but not {@link Audited}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class MultipleAuditParentsTest extends AbstractEntityTest {
private long childMultipleId = 1L;
private Integer siteMultipleId = null;
@Override
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(MappedGrandparentEntity.class);
cfg.addAnnotatedClass(MappedParentEntity.class);
cfg.addAnnotatedClass(ChildMultipleParentsEntity.class);
cfg.addAnnotatedClass(StrIntTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1
em.getTransaction().begin();
StrIntTestEntity siteMultiple = new StrIntTestEntity("data 1", 1);
em.persist(siteMultiple);
em.persist(new ChildMultipleParentsEntity(childMultipleId, "grandparent 1", "notAudited 1", "parent 1", "child 1", siteMultiple));
em.getTransaction().commit();
siteMultipleId = siteMultiple.getId();
}
@Test
public void testCreatedAuditTable() {
Set<String> expectedColumns = TestTools.makeSet("child", "parent", "relation_id", "grandparent", "id");
Set<String> unexpectedColumns = TestTools.makeSet("notAudited");
Table table = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildMultipleParentsEntity_AUD").getTable();
for (String columnName : expectedColumns) {
// Check whether expected column exists.
Assert.assertNotNull(table.getColumn(new Column(columnName)));
}
for (String columnName : unexpectedColumns) {
// Check whether unexpected column does not exist.
Assert.assertNull(table.getColumn(new Column(columnName)));
}
}
@Test
public void testMultipleAuditParents() {
// expectedMultipleChild.notAudited shall be null, because it is not audited.
ChildMultipleParentsEntity expectedMultipleChild = new ChildMultipleParentsEntity(childMultipleId, "grandparent 1", null, "parent 1", "child 1", new StrIntTestEntity("data 1", 1, siteMultipleId));
ChildMultipleParentsEntity child = getAuditReader().find(ChildMultipleParentsEntity.class, childMultipleId, 1);
Assert.assertEquals(expectedMultipleChild, child);
Assert.assertEquals(expectedMultipleChild.getRelation().getId(), child.getRelation().getId());
}
}

View File

@ -0,0 +1,73 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.MappedSuperclass;
import java.util.Set;
/**
* Tests mapping of child entity that declares one of its ancestors as audited with {@link Audited#auditParents()} property.
* All supperclasses are marked with {@link MappedSuperclass} annotation but not {@link Audited}.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class SingleAuditParentsTest extends AbstractEntityTest {
private long childSingleId = 1L;
private Integer siteSingleId = null;
@Override
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(MappedGrandparentEntity.class);
cfg.addAnnotatedClass(MappedParentEntity.class);
cfg.addAnnotatedClass(ChildSingleParentEntity.class);
cfg.addAnnotatedClass(StrIntTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1
em.getTransaction().begin();
StrIntTestEntity siteSingle = new StrIntTestEntity("data 1", 1);
em.persist(siteSingle);
em.persist(new ChildSingleParentEntity(childSingleId, "grandparent 1", "notAudited 1", "parent 1", "child 1", siteSingle));
em.getTransaction().commit();
siteSingleId = siteSingle.getId();
}
@Test
public void testCreatedAuditTable() {
Set<String> expectedColumns = TestTools.makeSet("child", "grandparent", "id");
Set<String> unexpectedColumns = TestTools.makeSet("parent", "relation_id", "notAudited");
Table table = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildSingleParentEntity_AUD").getTable();
for (String columnName : expectedColumns) {
// Check whether expected column exists.
Assert.assertNotNull(table.getColumn(new Column(columnName)));
}
for (String columnName : unexpectedColumns) {
// Check whether unexpected column does not exist.
Assert.assertNull(table.getColumn(new Column(columnName)));
}
}
@Test
public void testSingleAuditParent() {
// expectedSingleChild.parent, expectedSingleChild.relation and expectedSingleChild.notAudited shall be null, because they are not audited.
ChildSingleParentEntity expectedSingleChild = new ChildSingleParentEntity(childSingleId, "grandparent 1", null, null, "child 1", null);
ChildSingleParentEntity child = getAuditReader().find(ChildSingleParentEntity.class, childSingleId, 1);
Assert.assertEquals(expectedSingleChild, child);
Assert.assertNull(child.getRelation());
}
}

View File

@ -0,0 +1,74 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrIntTestEntity;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.Set;
/**
* Tests mapping of baby entity which declares its parent as audited with {@link Audited#auditParents()} property.
* Moreover, child class (mapped superclass of baby entity) declares grandparent entity as audited. In this case all
* attributes of baby class shall be audited.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class TotalAuditParentsTest extends AbstractEntityTest {
private long babyCompleteId = 1L;
private Integer siteCompleteId = null;
@Override
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(MappedGrandparentEntity.class);
cfg.addAnnotatedClass(MappedParentEntity.class);
cfg.addAnnotatedClass(StrIntTestEntity.class);
cfg.addAnnotatedClass(ChildCompleteEntity.class);
cfg.addAnnotatedClass(BabyCompleteEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1
em.getTransaction().begin();
StrIntTestEntity siteComplete = new StrIntTestEntity("data 1", 1);
em.persist(siteComplete);
em.persist(new BabyCompleteEntity(babyCompleteId, "grandparent 1", "notAudited 1", "parent 1", "child 1", siteComplete, "baby 1"));
em.getTransaction().commit();
siteCompleteId = siteComplete.getId();
}
@Test
public void testCreatedAuditTable() {
Set<String> expectedColumns = TestTools.makeSet("baby", "child", "parent", "relation_id", "grandparent", "id");
Set<String> unexpectedColumns = TestTools.makeSet("notAudited");
Table table = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.BabyCompleteEntity_AUD").getTable();
for (String columnName : expectedColumns) {
// Check whether expected column exists.
Assert.assertNotNull(table.getColumn(new Column(columnName)));
}
for (String columnName : unexpectedColumns) {
// Check whether unexpected column does not exist.
Assert.assertNull(table.getColumn(new Column(columnName)));
}
}
@Test
public void testCompleteAuditParents() {
// expectedBaby.notAudited shall be null, because it is not audited.
BabyCompleteEntity expectedBaby = new BabyCompleteEntity(babyCompleteId, "grandparent 1", null, "parent 1", "child 1", new StrIntTestEntity("data 1", 1, siteCompleteId), "baby 1");
BabyCompleteEntity baby = getAuditReader().find(BabyCompleteEntity.class, babyCompleteId, 1);
Assert.assertEquals(expectedBaby, baby);
Assert.assertEquals(expectedBaby.getRelation().getId(), baby.getRelation().getId());
}
}

View File

@ -0,0 +1,84 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.tools.TestTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Table;
import org.junit.Assert;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.Set;
/**
* Tests mapping of child entity which parent declares one of its ancestors as audited with {@link Audited#auditParents()}
* property. Child entity may mark explicitly its parent as audited or not.
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class TransitiveAuditParentsTest extends AbstractEntityTest {
private long childImpTransId = 1L;
private long childExpTransId = 2L;
@Override
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(MappedGrandparentEntity.class);
cfg.addAnnotatedClass(TransitiveParentEntity.class);
cfg.addAnnotatedClass(ImplicitTransitiveChildEntity.class);
cfg.addAnnotatedClass(ExplicitTransitiveChildEntity.class);
}
@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
// Revision 1
em.getTransaction().begin();
em.persist(new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 1", "notAudited 1", "parent 1", "child 1"));
em.getTransaction().commit();
// Revision 2
em.getTransaction().begin();
em.persist(new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 2", "notAudited 2", "parent 2", "child 2"));
em.getTransaction().commit();
}
@Test
public void testCreatedAuditTables() {
Table explicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ExplicitTransitiveChildEntity_AUD").getTable();
checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), TestTools.makeSet("notAudited"), explicitTransChildTable);
Table implicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ImplicitTransitiveChildEntity_AUD").getTable();
checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), TestTools.makeSet("notAudited"), implicitTransChildTable);
}
private void checkTableColumns(Set<String> expectedColumns, Set<String> unexpectedColumns, Table table) {
for (String columnName : expectedColumns) {
// Check whether expected column exists.
Assert.assertNotNull(table.getColumn(new Column(columnName)));
}
for (String columnName : unexpectedColumns) {
// Check whether unexpected column does not exist.
Assert.assertNull(table.getColumn(new Column(columnName)));
}
}
@Test
public void testImplicitTransitiveAuditParents() {
// expectedChild.notAudited shall be null, because it is not audited.
ImplicitTransitiveChildEntity expectedChild = new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 1", null, "parent 1", "child 1");
ImplicitTransitiveChildEntity child = getAuditReader().find(ImplicitTransitiveChildEntity.class, childImpTransId, 1);
Assert.assertEquals(expectedChild, child);
}
@Test
public void testExplicitTransitiveAuditParents() {
// expectedChild.notAudited shall be null, because it is not audited.
ExplicitTransitiveChildEntity expectedChild = new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 2", null, "parent 2", "child 2");
ExplicitTransitiveChildEntity child = getAuditReader().find(ExplicitTransitiveChildEntity.class, childExpTransId, 2);
Assert.assertEquals(expectedChild, child);
}
}

View File

@ -0,0 +1,53 @@
package org.hibernate.envers.test.integration.superclass.auditparents;
import org.hibernate.envers.Audited;
import javax.persistence.MappedSuperclass;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@MappedSuperclass
@Audited(auditParents = {MappedGrandparentEntity.class})
public class TransitiveParentEntity extends MappedGrandparentEntity {
private String parent;
public TransitiveParentEntity() {
super(null, null, null);
}
public TransitiveParentEntity(Long id, String grandparent, String notAudited, String parent) {
super(id, grandparent, notAudited);
this.parent = parent;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TransitiveParentEntity)) return false;
if (!super.equals(o)) return false;
TransitiveParentEntity that = (TransitiveParentEntity) o;
if (parent != null ? !parent.equals(that.parent) : that.parent != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (parent != null ? parent.hashCode() : 0);
return result;
}
public String toString() {
return "TransitiveParentEntity(" + super.toString() + ", parent = " + parent + ")";
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
}