diff --git a/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java b/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java index 61e42b0d80..b23990c821 100644 --- a/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java +++ b/envers/src/main/java/org/hibernate/envers/event/AuditEventListener.java @@ -234,11 +234,15 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj); RevisionType revType = (RevisionType) changeData.getData().get(verCfg.getAuditEntCfg().getRevisionTypePropName()); + // This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass + // of relatedEntityName). + String realRelatedEntityName = event.getSession().bestGuessEntityName(relatedObj); + // By default, the nested work unit is a collection change work unit. - AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(event.getSession(), relatedEntityName, verCfg, + AuditWorkUnit nestedWorkUnit = new CollectionChangeWorkUnit(event.getSession(), realRelatedEntityName, verCfg, relatedId, relatedObj); - verSync.addWorkUnit(new FakeBidirectionalRelationWorkUnit(event.getSession(), relatedEntityName, verCfg, + verSync.addWorkUnit(new FakeBidirectionalRelationWorkUnit(event.getSession(), realRelatedEntityName, verCfg, relatedId, referencingPropertyName, event.getAffectedOwnerOrNull(), rd, revType, changeData.getChangedElementIndex(), nestedWorkUnit)); } diff --git a/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdChildEntity.java b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdChildEntity.java new file mode 100644 index 0000000000..5eaedc2a16 --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdChildEntity.java @@ -0,0 +1,63 @@ +package org.hibernate.envers.test.entities.onetomany.detached; + +import org.hibernate.envers.Audited; + +import javax.persistence.*; + +/** + * Entity for {@link org.hibernate.envers.test.integration.onetomany.detached.JoinColumnBidirectionalListWithInheritance} test. + * Owned child side of the relation. + * @author Adam Warski (adam at warski dot org) + */ +@Entity +@DiscriminatorValue("2") +@Audited +public class ListJoinColumnBidirectionalInheritanceRefEdChildEntity extends ListJoinColumnBidirectionalInheritanceRefEdParentEntity { + private String childData; + + public ListJoinColumnBidirectionalInheritanceRefEdChildEntity() { } + + public ListJoinColumnBidirectionalInheritanceRefEdChildEntity(Integer id, String parentData, ListJoinColumnBidirectionalInheritanceRefIngEntity owner, String childData) { + super(id, parentData, owner); + this.childData = childData; + } + + public ListJoinColumnBidirectionalInheritanceRefEdChildEntity(String parentData, ListJoinColumnBidirectionalInheritanceRefIngEntity owner, String childData) { + super(parentData, owner); + this.childData = childData; + } + + public String getChildData() { + return childData; + } + + public void setChildData(String childData) { + this.childData = childData; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + ListJoinColumnBidirectionalInheritanceRefEdChildEntity that = (ListJoinColumnBidirectionalInheritanceRefEdChildEntity) o; + + //noinspection RedundantIfStatement + if (childData != null ? !childData.equals(that.childData) : that.childData != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (childData != null ? childData.hashCode() : 0); + return result; + } + + public String toString() { + return "ListJoinColumnBidirectionalInheritanceRefEdChildEntity(id = " + getId() + + ", parentData = " + getParentData() + ", childData = " + childData + ")"; + } +} \ No newline at end of file diff --git a/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdParentEntity.java b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdParentEntity.java new file mode 100644 index 0000000000..60dbe094ec --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefEdParentEntity.java @@ -0,0 +1,88 @@ +package org.hibernate.envers.test.entities.onetomany.detached; + +import org.hibernate.envers.Audited; + +import javax.persistence.*; + +/** + * Entity for {@link org.hibernate.envers.test.integration.onetomany.detached.JoinColumnBidirectionalListWithInheritance} test. + * Owned parent side of the relation. + * @author Adam Warski (adam at warski dot org) + */ +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.INTEGER) +@DiscriminatorValue("1") +@Audited +public class ListJoinColumnBidirectionalInheritanceRefEdParentEntity { + @Id + @GeneratedValue + private Integer id; + + private String parentData; + + @ManyToOne + @JoinColumn(name = "some_join_column", insertable = false, updatable = false) + private ListJoinColumnBidirectionalInheritanceRefIngEntity owner; + + public ListJoinColumnBidirectionalInheritanceRefEdParentEntity() { } + + public ListJoinColumnBidirectionalInheritanceRefEdParentEntity(Integer id, String parentData, ListJoinColumnBidirectionalInheritanceRefIngEntity owner) { + this.id = id; + this.parentData = parentData; + this.owner = owner; + } + + public ListJoinColumnBidirectionalInheritanceRefEdParentEntity(String parentData, ListJoinColumnBidirectionalInheritanceRefIngEntity owner) { + this.parentData = parentData; + this.owner = owner; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public ListJoinColumnBidirectionalInheritanceRefIngEntity getOwner() { + return owner; + } + + public void setOwner(ListJoinColumnBidirectionalInheritanceRefIngEntity owner) { + this.owner = owner; + } + + public String getParentData() { + return parentData; + } + + public void setParentData(String parentData) { + this.parentData = parentData; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListJoinColumnBidirectionalInheritanceRefEdParentEntity)) return false; + + ListJoinColumnBidirectionalInheritanceRefEdParentEntity that = (ListJoinColumnBidirectionalInheritanceRefEdParentEntity) o; + + if (parentData != null ? !parentData.equals(that.parentData) : that.parentData != null) return false; + //noinspection RedundantIfStatement + if (id != null ? !id.equals(that.id) : that.id != null) return false; + + return true; + } + + public int hashCode() { + int result; + result = (id != null ? id.hashCode() : 0); + result = 31 * result + (parentData != null ? parentData.hashCode() : 0); + return result; + } + + public String toString() { + return "ListJoinColumnBidirectionalInheritanceRefEdParentEntity(id = " + id + ", parentData = " + parentData + ")"; + } +} \ No newline at end of file diff --git a/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefIngEntity.java b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefIngEntity.java new file mode 100644 index 0000000000..34b0caf352 --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/entities/onetomany/detached/ListJoinColumnBidirectionalInheritanceRefIngEntity.java @@ -0,0 +1,90 @@ +package org.hibernate.envers.test.entities.onetomany.detached; + +import org.hibernate.envers.Audited; +import org.hibernate.envers.AuditMappedBy; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; + +/** + * Entity for {@link org.hibernate.envers.test.integration.onetomany.detached.JoinColumnBidirectionalListWithInheritance} test. + * Owning side of the relation. + * @author Adam Warski (adam at warski dot org) + */ +@Entity +@Audited +public class ListJoinColumnBidirectionalInheritanceRefIngEntity { + @Id + @GeneratedValue + private Integer id; + + private String data; + + @OneToMany + @JoinColumn(name = "some_join_column") + @AuditMappedBy(mappedBy = "owner") + private List references; + + public ListJoinColumnBidirectionalInheritanceRefIngEntity() { } + + public ListJoinColumnBidirectionalInheritanceRefIngEntity(Integer id, String data, ListJoinColumnBidirectionalInheritanceRefEdParentEntity... references) { + this.id = id; + this.data = data; + this.references = new ArrayList(); + this.references.addAll(Arrays.asList(references)); + } + + public ListJoinColumnBidirectionalInheritanceRefIngEntity(String data, ListJoinColumnBidirectionalInheritanceRefEdParentEntity... references) { + this(null, data, references); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public List getReferences() { + return references; + } + + public void setReferences(List references) { + this.references = references; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListJoinColumnBidirectionalInheritanceRefIngEntity)) return false; + + ListJoinColumnBidirectionalInheritanceRefIngEntity that = (ListJoinColumnBidirectionalInheritanceRefIngEntity) o; + + if (data != null ? !data.equals(that.data) : that.data != null) return false; + //noinspection RedundantIfStatement + if (id != null ? !id.equals(that.id) : that.id != null) return false; + + return true; + } + + public int hashCode() { + int result; + result = (id != null ? id.hashCode() : 0); + result = 31 * result + (data != null ? data.hashCode() : 0); + return result; + } + + public String toString() { + return "ListJoinColumnBidirectionalInheritanceRefIngEntity(id = " + id + ", data = " + data + ")"; + } +} \ No newline at end of file diff --git a/envers/src/test/java/org/hibernate/envers/test/integration/onetomany/detached/JoinColumnBidirectionalListWithInheritance.java b/envers/src/test/java/org/hibernate/envers/test/integration/onetomany/detached/JoinColumnBidirectionalListWithInheritance.java new file mode 100644 index 0000000000..490e5cab44 --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/integration/onetomany/detached/JoinColumnBidirectionalListWithInheritance.java @@ -0,0 +1,155 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.envers.test.integration.onetomany.detached; + +import org.hibernate.ejb.Ejb3Configuration; +import org.hibernate.envers.test.AbstractEntityTest; +import org.hibernate.envers.test.entities.onetomany.detached.ListJoinColumnBidirectionalInheritanceRefEdChildEntity; +import org.hibernate.envers.test.entities.onetomany.detached.ListJoinColumnBidirectionalInheritanceRefEdParentEntity; +import org.hibernate.envers.test.entities.onetomany.detached.ListJoinColumnBidirectionalInheritanceRefIngEntity; +import static org.hibernate.envers.test.tools.TestTools.checkList; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; + +import javax.persistence.EntityManager; +import java.util.Arrays; + +/** + * Test for a "fake" bidirectional mapping where one side uses @OneToMany+@JoinColumn (and thus owns the relatin), + * and the other uses a @ManyToOne(insertable=false, updatable=false). + * @author Adam Warski (adam at warski dot org) + */ +public class JoinColumnBidirectionalListWithInheritance extends AbstractEntityTest { + private Integer ed1_id; + private Integer ed2_id; + + private Integer ing1_id; + private Integer ing2_id; + + public void configure(Ejb3Configuration cfg) { + cfg.addAnnotatedClass(ListJoinColumnBidirectionalInheritanceRefIngEntity.class); + cfg.addAnnotatedClass(ListJoinColumnBidirectionalInheritanceRefEdChildEntity.class); + cfg.addAnnotatedClass(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class); + } + + @Test(enabled = true) + public void createData() { + EntityManager em = getEntityManager(); + + ListJoinColumnBidirectionalInheritanceRefEdParentEntity ed1 = new ListJoinColumnBidirectionalInheritanceRefEdChildEntity("ed1", null, "ed1 child"); + ListJoinColumnBidirectionalInheritanceRefEdParentEntity ed2 = new ListJoinColumnBidirectionalInheritanceRefEdChildEntity("ed2", null, "ed2 child"); + + ListJoinColumnBidirectionalInheritanceRefIngEntity ing1 = new ListJoinColumnBidirectionalInheritanceRefIngEntity("coll1", ed1); + ListJoinColumnBidirectionalInheritanceRefIngEntity ing2 = new ListJoinColumnBidirectionalInheritanceRefIngEntity("coll1", ed2); + + // Revision 1 (ing1: ed1, ing2: ed2) + em.getTransaction().begin(); + + em.persist(ed1); + em.persist(ed2); + em.persist(ing1); + em.persist(ing2); + + em.getTransaction().commit(); + + // Revision 2 (ing1: ed1, ed2) + em.getTransaction().begin(); + + ing1 = em.find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1.getId()); + ing2 = em.find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing2.getId()); + ed1 = em.find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed1.getId()); + ed2 = em.find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2.getId()); + + ing2.getReferences().remove(ed2); + ing1.getReferences().add(ed2); + + em.getTransaction().commit(); + em.clear(); + + // + + ing1_id = ing1.getId(); + ing2_id = ing2.getId(); + + ed1_id = ed1.getId(); + ed2_id = ed2.getId(); + } + + @Test(enabled = true, dependsOnMethods = "createData") + public void testRevisionsCounts() { + assertEquals(Arrays.asList(1, 2), getAuditReader().getRevisions(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1_id)); + assertEquals(Arrays.asList(1, 2), getAuditReader().getRevisions(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing2_id)); + + assertEquals(Arrays.asList(1), getAuditReader().getRevisions(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed1_id)); + assertEquals(Arrays.asList(1, 2), getAuditReader().getRevisions(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2_id)); + } + + @Test(enabled = true, dependsOnMethods = "createData") + public void testHistoryOfIng1() { + ListJoinColumnBidirectionalInheritanceRefEdParentEntity ed1 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed1_id); + ListJoinColumnBidirectionalInheritanceRefEdParentEntity ed2 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2_id); + + ListJoinColumnBidirectionalInheritanceRefIngEntity rev1 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1_id, 1); + ListJoinColumnBidirectionalInheritanceRefIngEntity rev2 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1_id, 2); + + assertTrue(checkList(rev1.getReferences(), ed1)); + assertTrue(checkList(rev2.getReferences(), ed1, ed2)); + } + + @Test(enabled = true, dependsOnMethods = "createData") + public void testHistoryOfIng2() { + ListJoinColumnBidirectionalInheritanceRefEdParentEntity ed2 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2_id); + + ListJoinColumnBidirectionalInheritanceRefIngEntity rev1 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing2_id, 1); + ListJoinColumnBidirectionalInheritanceRefIngEntity rev2 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing2_id, 2); + + assertTrue(checkList(rev1.getReferences(), ed2)); + assertTrue(checkList(rev2.getReferences())); + } + + @Test(enabled = true, dependsOnMethods = "createData") + public void testHistoryOfEd1() { + ListJoinColumnBidirectionalInheritanceRefIngEntity ing1 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1_id); + + ListJoinColumnBidirectionalInheritanceRefEdParentEntity rev1 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed1_id, 1); + ListJoinColumnBidirectionalInheritanceRefEdParentEntity rev2 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed1_id, 2); + + assertTrue(rev1.getOwner().equals(ing1)); + assertTrue(rev2.getOwner().equals(ing1)); + } + + @Test(enabled = true, dependsOnMethods = "createData") + public void testHistoryOfEd2() { + ListJoinColumnBidirectionalInheritanceRefIngEntity ing1 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing1_id); + ListJoinColumnBidirectionalInheritanceRefIngEntity ing2 = getEntityManager().find(ListJoinColumnBidirectionalInheritanceRefIngEntity.class, ing2_id); + + ListJoinColumnBidirectionalInheritanceRefEdParentEntity rev1 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2_id, 1); + ListJoinColumnBidirectionalInheritanceRefEdParentEntity rev2 = getAuditReader().find(ListJoinColumnBidirectionalInheritanceRefEdParentEntity.class, ed2_id, 2); + + assertTrue(rev1.getOwner().equals(ing2)); + assertTrue(rev2.getOwner().equals(ing1)); + } + +} \ No newline at end of file