From efc9377b3177d0f29701c96d591be362ea9b1f69 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Sat, 18 Jun 2011 10:04:52 +0200 Subject: [PATCH 1/4] HHH-5917 - Fix and test --- .../java/org/hibernate/envers/Audited.java | 9 ++ .../reader/AuditedPropertiesReader.java | 78 ++++++++- .../auditparents/AuditParentsTest.java | 153 ++++++++++++++++++ .../auditparents/BabyCompleteEntity.java | 53 ++++++ .../auditparents/ChildCompleteEntity.java | 54 +++++++ .../ChildMultipleParentsEntity.java | 55 +++++++ .../auditparents/ChildSingleParentEntity.java | 54 +++++++ .../ExplicitTransitiveChildEntity.java | 53 ++++++ .../ImplicitTransitiveChildEntity.java | 53 ++++++ .../auditparents/MappedGrandparentEntity.java | 74 +++++++++ .../auditparents/MappedParentEntity.java | 61 +++++++ .../auditparents/TransitiveParentEntity.java | 53 ++++++ 12 files changed, 745 insertions(+), 5 deletions(-) create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/BabyCompleteEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildCompleteEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildMultipleParentsEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildSingleParentEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ExplicitTransitiveChildEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ImplicitTransitiveChildEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedGrandparentEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedParentEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveParentEntity.java diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java b/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java index 01dc2134c1..bd7fdcffba 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java @@ -33,6 +33,7 @@ import java.lang.annotation.Target; * When applied to a field, indicates that this field should be audited. * @author Adam Warski (adam at warski dot org) * @author Tomasz Bech + * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @@ -45,4 +46,12 @@ public @interface Audited { * This is useful for dictionary-like entities, which don't change and don't need to be 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 {}; } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java index 090baabd43..f4a8fa2537 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java @@ -3,6 +3,7 @@ package org.hibernate.envers.configuration.metadata.reader; import static org.hibernate.envers.tools.Tools.newHashSet; import java.lang.annotation.Annotation; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -31,6 +32,7 @@ import org.hibernate.MappingException; * @author Adam Warski (adam at warski dot org) * @author Erik-Berndt Scheper * @author Hern&aacut;n Chanfreau + * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ public class AuditedPropertiesReader { protected final ModificationStore defaultStore; @@ -64,10 +66,50 @@ public class AuditedPropertiesReader { // First reading the access types for the persistent properties. readPersistentPropertiesAccess(); - // Adding all properties from the given class. - addPropertiesFromClass(persistentPropertiesSource.getXClass()); + // Retrieve classes that are explicitly marked for auditing process by any superclass of currently mapped + // entity or itself. + XClass clazz = persistentPropertiesSource.getXClass(); + Set declaredAuditedSuperclasses = new HashSet(); + 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 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() { Iterator propertyIter = persistentPropertiesSource.getPropertyIterator(); while (propertyIter.hasNext()) { @@ -80,8 +122,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 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 declaredAuditedSuperclasses) { + Audited allClassAudited = computeAuditConfiguration(clazz, declaredAuditedSuperclasses); + //look in the class addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited); addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited); @@ -89,7 +157,7 @@ public class AuditedPropertiesReader { if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) { XClass superclazz = clazz.getSuperclass(); if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) { - addPropertiesFromClass(superclazz); + addPropertiesFromClass(superclazz, declaredAuditedSuperclasses); } } } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java new file mode 100644 index 0000000000..723846a7d5 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java @@ -0,0 +1,153 @@ +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 several configurations of entity hierarchy that utilizes {@link Audited#auditParents()} property. + * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) + */ +public class AuditParentsTest extends AbstractEntityTest { + private long childSingleId = 1L; + private long childMultipleId = 2L; + private long childImpTransId = 3L; + private long childExpTransId = 4L; + private long babyCompleteId = 5L; + private Integer siteSingleId = null; + private Integer siteMultipleId = null; + private Integer siteCompleteId = null; + + @Override + public void configure(Ejb3Configuration cfg) { + cfg.addAnnotatedClass(MappedGrandparentEntity.class); + cfg.addAnnotatedClass(MappedParentEntity.class); + cfg.addAnnotatedClass(ChildSingleParentEntity.class); + cfg.addAnnotatedClass(ChildMultipleParentsEntity.class); + cfg.addAnnotatedClass(TransitiveParentEntity.class); + cfg.addAnnotatedClass(ImplicitTransitiveChildEntity.class); + cfg.addAnnotatedClass(ExplicitTransitiveChildEntity.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 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(); + + // Revision 2 + em.getTransaction().begin(); + StrIntTestEntity siteMultiple = new StrIntTestEntity("data 2", 2); + em.persist(siteMultiple); + em.persist(new ChildMultipleParentsEntity(childMultipleId, "grandparent 2", "notAudited 2", "parent 2", "child 2", siteMultiple)); + em.getTransaction().commit(); + siteMultipleId = siteMultiple.getId(); + + // Revision 3 + em.getTransaction().begin(); + em.persist(new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 3", "notAudited 3", "parent 3", "child 3")); + em.getTransaction().commit(); + + // Revision 4 + em.getTransaction().begin(); + em.persist(new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 4", "notAudited 4", "parent 4", "child 4")); + em.getTransaction().commit(); + + // Revision 5 + em.getTransaction().begin(); + StrIntTestEntity siteComplete = new StrIntTestEntity("data 5", 5); + em.persist(siteComplete); + em.persist(new BabyCompleteEntity(babyCompleteId, "grandparent 5", "notAudited 5", "parent 5", "child 5", siteComplete, "baby 5")); + em.getTransaction().commit(); + siteCompleteId = siteComplete.getId(); + } + + @Test + public void testCreatedAuditTables() { + Table babyCompleteTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.BabyCompleteEntity_AUD").getTable(); + checkTableColumns(TestTools.makeSet("baby", "child", "parent", "relation_id", "grandparent", "id"), babyCompleteTable); + + Table explicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ExplicitTransitiveChildEntity_AUD").getTable(); + checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), explicitTransChildTable); + + Table implicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ImplicitTransitiveChildEntity_AUD").getTable(); + checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), implicitTransChildTable); + + Table multipleParentChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildMultipleParentsEntity_AUD").getTable(); + checkTableColumns(TestTools.makeSet("child", "parent", "relation_id", "grandparent", "id"), multipleParentChildTable); + + Table singleParentChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildSingleParentEntity_AUD").getTable(); + checkTableColumns(TestTools.makeSet("child", "grandparent", "id"), singleParentChildTable); + } + + @SuppressWarnings("unchecked") + private void checkTableColumns(Set expectedColumns, Table table) { + for (String columnName : expectedColumns) { + // Check whether expected column exists. + Assert.assertNotNull(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()); + } + + @Test + public void testMultipleAuditParents() { + // expectedMultipleChild.notAudited shall be null, because it is not audited. + ChildMultipleParentsEntity expectedMultipleChild = new ChildMultipleParentsEntity(childMultipleId, "grandparent 2", null, "parent 2", "child 2", new StrIntTestEntity("data 2", 2, siteMultipleId)); + ChildMultipleParentsEntity child = getAuditReader().find(ChildMultipleParentsEntity.class, childMultipleId, 2); + Assert.assertEquals(expectedMultipleChild, child); + Assert.assertEquals(expectedMultipleChild.getRelation().getId(), child.getRelation().getId()); + } + + @Test + public void testImplicitTransitiveAuditParents() { + // expectedChild.notAudited shall be null, because it is not audited. + ImplicitTransitiveChildEntity expectedChild = new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 3", null, "parent 3", "child 3"); + ImplicitTransitiveChildEntity child = getAuditReader().find(ImplicitTransitiveChildEntity.class, childImpTransId, 3); + Assert.assertEquals(expectedChild, child); + } + + @Test + public void testExplicitTransitiveAuditParents() { + // expectedChild.notAudited shall be null, because it is not audited. + ExplicitTransitiveChildEntity expectedChild = new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 4", null, "parent 4", "child 4"); + ExplicitTransitiveChildEntity child = getAuditReader().find(ExplicitTransitiveChildEntity.class, childExpTransId, 4); + Assert.assertEquals(expectedChild, child); + } + + @Test + public void testCompleteAuditParents() { + // expectedBaby.notAudited shall be null, because it is not audited. + BabyCompleteEntity expectedBaby = new BabyCompleteEntity(babyCompleteId, "grandparent 5", null, "parent 5", "child 5", new StrIntTestEntity("data 5", 5, siteCompleteId), "baby 5"); + BabyCompleteEntity baby = getAuditReader().find(BabyCompleteEntity.class, babyCompleteId, 5); + Assert.assertEquals(expectedBaby, baby); + Assert.assertEquals(expectedBaby.getRelation().getId(), baby.getRelation().getId()); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/BabyCompleteEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/BabyCompleteEntity.java new file mode 100644 index 0000000000..ae564aaea0 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/BabyCompleteEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildCompleteEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildCompleteEntity.java new file mode 100644 index 0000000000..b8152ac592 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildCompleteEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildMultipleParentsEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildMultipleParentsEntity.java new file mode 100644 index 0000000000..2029067fd0 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildMultipleParentsEntity.java @@ -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; + } +} + diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildSingleParentEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildSingleParentEntity.java new file mode 100644 index 0000000000..2670f3eabb --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ChildSingleParentEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ExplicitTransitiveChildEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ExplicitTransitiveChildEntity.java new file mode 100644 index 0000000000..b392323571 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ExplicitTransitiveChildEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ImplicitTransitiveChildEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ImplicitTransitiveChildEntity.java new file mode 100644 index 0000000000..a5c010374a --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/ImplicitTransitiveChildEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedGrandparentEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedGrandparentEntity.java new file mode 100644 index 0000000000..79a4f20ff3 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedGrandparentEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedParentEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedParentEntity.java new file mode 100644 index 0000000000..9d83b0e754 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MappedParentEntity.java @@ -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; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveParentEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveParentEntity.java new file mode 100644 index 0000000000..e58c979f65 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveParentEntity.java @@ -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; + } +} From 8a750e28fc84b0a8b9c4f2275c91c3c7e4755bc2 Mon Sep 17 00:00:00 2001 From: Lukasz Antoniak Date: Mon, 27 Jun 2011 21:52:40 +0200 Subject: [PATCH 2/4] HHH-5917 - Split test cases and updated documentation --- .../docbook/en-US/content/configuration.xml | 8 + .../auditparents/AuditParentsTest.java | 153 ------------------ .../MultipleAuditParentsTest.java | 73 +++++++++ .../auditparents/SingleAuditParentsTest.java | 73 +++++++++ .../auditparents/TotalAuditParentsTest.java | 74 +++++++++ .../TransitiveAuditParentsTest.java | 84 ++++++++++ 6 files changed, 312 insertions(+), 153 deletions(-) delete mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java diff --git a/hibernate-documentation/envers/src/main/docbook/en-US/content/configuration.xml b/hibernate-documentation/envers/src/main/docbook/en-US/content/configuration.xml index 8a371fa16b..e15ee0d25b 100644 --- a/hibernate-documentation/envers/src/main/docbook/en-US/content/configuration.xml +++ b/hibernate-documentation/envers/src/main/docbook/en-US/content/configuration.xml @@ -374,6 +374,14 @@ versions of your entity, the relation will always point to the "current" related entity. + + 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 auditParents attribute of + @Audited annotation. If any @MappedSuperclass + (or any of it's properties) is marked as @Audited, it's behavior is implicitly + inherited by all audited subclasses. + + diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java deleted file mode 100644 index 723846a7d5..0000000000 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/AuditParentsTest.java +++ /dev/null @@ -1,153 +0,0 @@ -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 several configurations of entity hierarchy that utilizes {@link Audited#auditParents()} property. - * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) - */ -public class AuditParentsTest extends AbstractEntityTest { - private long childSingleId = 1L; - private long childMultipleId = 2L; - private long childImpTransId = 3L; - private long childExpTransId = 4L; - private long babyCompleteId = 5L; - private Integer siteSingleId = null; - private Integer siteMultipleId = null; - private Integer siteCompleteId = null; - - @Override - public void configure(Ejb3Configuration cfg) { - cfg.addAnnotatedClass(MappedGrandparentEntity.class); - cfg.addAnnotatedClass(MappedParentEntity.class); - cfg.addAnnotatedClass(ChildSingleParentEntity.class); - cfg.addAnnotatedClass(ChildMultipleParentsEntity.class); - cfg.addAnnotatedClass(TransitiveParentEntity.class); - cfg.addAnnotatedClass(ImplicitTransitiveChildEntity.class); - cfg.addAnnotatedClass(ExplicitTransitiveChildEntity.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 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(); - - // Revision 2 - em.getTransaction().begin(); - StrIntTestEntity siteMultiple = new StrIntTestEntity("data 2", 2); - em.persist(siteMultiple); - em.persist(new ChildMultipleParentsEntity(childMultipleId, "grandparent 2", "notAudited 2", "parent 2", "child 2", siteMultiple)); - em.getTransaction().commit(); - siteMultipleId = siteMultiple.getId(); - - // Revision 3 - em.getTransaction().begin(); - em.persist(new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 3", "notAudited 3", "parent 3", "child 3")); - em.getTransaction().commit(); - - // Revision 4 - em.getTransaction().begin(); - em.persist(new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 4", "notAudited 4", "parent 4", "child 4")); - em.getTransaction().commit(); - - // Revision 5 - em.getTransaction().begin(); - StrIntTestEntity siteComplete = new StrIntTestEntity("data 5", 5); - em.persist(siteComplete); - em.persist(new BabyCompleteEntity(babyCompleteId, "grandparent 5", "notAudited 5", "parent 5", "child 5", siteComplete, "baby 5")); - em.getTransaction().commit(); - siteCompleteId = siteComplete.getId(); - } - - @Test - public void testCreatedAuditTables() { - Table babyCompleteTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.BabyCompleteEntity_AUD").getTable(); - checkTableColumns(TestTools.makeSet("baby", "child", "parent", "relation_id", "grandparent", "id"), babyCompleteTable); - - Table explicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ExplicitTransitiveChildEntity_AUD").getTable(); - checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), explicitTransChildTable); - - Table implicitTransChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ImplicitTransitiveChildEntity_AUD").getTable(); - checkTableColumns(TestTools.makeSet("child", "parent", "grandparent", "id"), implicitTransChildTable); - - Table multipleParentChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildMultipleParentsEntity_AUD").getTable(); - checkTableColumns(TestTools.makeSet("child", "parent", "relation_id", "grandparent", "id"), multipleParentChildTable); - - Table singleParentChildTable = getCfg().getClassMapping("org.hibernate.envers.test.integration.superclass.auditparents.ChildSingleParentEntity_AUD").getTable(); - checkTableColumns(TestTools.makeSet("child", "grandparent", "id"), singleParentChildTable); - } - - @SuppressWarnings("unchecked") - private void checkTableColumns(Set expectedColumns, Table table) { - for (String columnName : expectedColumns) { - // Check whether expected column exists. - Assert.assertNotNull(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()); - } - - @Test - public void testMultipleAuditParents() { - // expectedMultipleChild.notAudited shall be null, because it is not audited. - ChildMultipleParentsEntity expectedMultipleChild = new ChildMultipleParentsEntity(childMultipleId, "grandparent 2", null, "parent 2", "child 2", new StrIntTestEntity("data 2", 2, siteMultipleId)); - ChildMultipleParentsEntity child = getAuditReader().find(ChildMultipleParentsEntity.class, childMultipleId, 2); - Assert.assertEquals(expectedMultipleChild, child); - Assert.assertEquals(expectedMultipleChild.getRelation().getId(), child.getRelation().getId()); - } - - @Test - public void testImplicitTransitiveAuditParents() { - // expectedChild.notAudited shall be null, because it is not audited. - ImplicitTransitiveChildEntity expectedChild = new ImplicitTransitiveChildEntity(childImpTransId, "grandparent 3", null, "parent 3", "child 3"); - ImplicitTransitiveChildEntity child = getAuditReader().find(ImplicitTransitiveChildEntity.class, childImpTransId, 3); - Assert.assertEquals(expectedChild, child); - } - - @Test - public void testExplicitTransitiveAuditParents() { - // expectedChild.notAudited shall be null, because it is not audited. - ExplicitTransitiveChildEntity expectedChild = new ExplicitTransitiveChildEntity(childExpTransId, "grandparent 4", null, "parent 4", "child 4"); - ExplicitTransitiveChildEntity child = getAuditReader().find(ExplicitTransitiveChildEntity.class, childExpTransId, 4); - Assert.assertEquals(expectedChild, child); - } - - @Test - public void testCompleteAuditParents() { - // expectedBaby.notAudited shall be null, because it is not audited. - BabyCompleteEntity expectedBaby = new BabyCompleteEntity(babyCompleteId, "grandparent 5", null, "parent 5", "child 5", new StrIntTestEntity("data 5", 5, siteCompleteId), "baby 5"); - BabyCompleteEntity baby = getAuditReader().find(BabyCompleteEntity.class, babyCompleteId, 5); - Assert.assertEquals(expectedBaby, baby); - Assert.assertEquals(expectedBaby.getRelation().getId(), baby.getRelation().getId()); - } -} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java new file mode 100644 index 0000000000..369133496d --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java @@ -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 expectedColumns = TestTools.makeSet("child", "parent", "relation_id", "grandparent", "id"); + Set 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()); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java new file mode 100644 index 0000000000..37c8b9f374 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java @@ -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 expectedColumns = TestTools.makeSet("child", "grandparent", "id"); + Set 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()); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java new file mode 100644 index 0000000000..0176ac0b91 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java @@ -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 expectedColumns = TestTools.makeSet("baby", "child", "parent", "relation_id", "grandparent", "id"); + Set 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()); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java new file mode 100644 index 0000000000..9cfa82d7de --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java @@ -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 expectedColumns, Set 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); + } +} From d3e889bac4be8ca332827f4d02a18409806783dc Mon Sep 17 00:00:00 2001 From: Adam Warski Date: Wed, 29 Jun 2011 18:27:35 +0200 Subject: [PATCH 3/4] HHH-5917: improving documentation --- .../src/main/java/org/hibernate/envers/Audited.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java b/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java index bd7fdcffba..4df903a6a4 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/Audited.java @@ -48,10 +48,14 @@ public @interface 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. + * @return Specifies the superclasses for which properties should be audited, even if the superclasses are not + * annotated with {@link Audited}. Causes all properties of the listed classes to be audited, just as if the + * classes had {@link Audited} annotation applied on the class level. + * + * The scope of this functionality is limited to the class hierarchy of the annotated entity. + * + * If a parent type lists any of its parent types using this attribute, all properties in the specified classes + * will also be audited. */ Class[] auditParents() default {}; } From 5bce79192c0f9bdc534eecb31c7c347a5888671d Mon Sep 17 00:00:00 2001 From: Michal Skowronek Date: Thu, 13 Oct 2011 20:12:33 +0200 Subject: [PATCH 4/4] HHH-5917 Migrated test cases to TestNG --- .../auditparents/MultipleAuditParentsTest.java | 9 ++++----- .../superclass/auditparents/SingleAuditParentsTest.java | 9 ++++----- .../superclass/auditparents/TotalAuditParentsTest.java | 9 ++++----- .../auditparents/TransitiveAuditParentsTest.java | 9 ++++----- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java index 369133496d..f768d77d4a 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/MultipleAuditParentsTest.java @@ -3,13 +3,13 @@ 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 org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; import javax.persistence.EntityManager; import javax.persistence.MappedSuperclass; @@ -32,8 +32,7 @@ public class MultipleAuditParentsTest extends AbstractEntityTest { cfg.addAnnotatedClass(StrIntTestEntity.class); } - @Test - @Priority(10) + @BeforeClass(dependsOnMethods = "init") public void initData() { EntityManager em = getEntityManager(); // Revision 1 diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java index 37c8b9f374..c8a7fcfec2 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/SingleAuditParentsTest.java @@ -3,13 +3,13 @@ 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 org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; import javax.persistence.EntityManager; import javax.persistence.MappedSuperclass; @@ -32,8 +32,7 @@ public class SingleAuditParentsTest extends AbstractEntityTest { cfg.addAnnotatedClass(StrIntTestEntity.class); } - @Test - @Priority(10) + @BeforeClass(dependsOnMethods = "init") public void initData() { EntityManager em = getEntityManager(); // Revision 1 diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java index 0176ac0b91..5a6f55ea8f 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TotalAuditParentsTest.java @@ -3,13 +3,13 @@ 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 org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; import javax.persistence.EntityManager; import java.util.Set; @@ -33,8 +33,7 @@ public class TotalAuditParentsTest extends AbstractEntityTest { cfg.addAnnotatedClass(BabyCompleteEntity.class); } - @Test - @Priority(10) + @BeforeClass(dependsOnMethods = "init") public void initData() { EntityManager em = getEntityManager(); // Revision 1 diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java index 9cfa82d7de..3d8efc3041 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/superclass/auditparents/TransitiveAuditParentsTest.java @@ -3,12 +3,12 @@ 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 org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; import javax.persistence.EntityManager; import java.util.Set; @@ -30,8 +30,7 @@ public class TransitiveAuditParentsTest extends AbstractEntityTest { cfg.addAnnotatedClass(ExplicitTransitiveChildEntity.class); } - @Test - @Priority(10) + @BeforeClass(dependsOnMethods = "init") public void initData() { EntityManager em = getEntityManager();