HHH-3602: bug fix with test (generating a CollectionChangeWorkUnit for the proper entity in case a relation is owned by a superclass, when inheritance is used)

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15565 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Adam Warski 2008-11-14 15:16:23 +00:00
parent edf3822cfb
commit 044efaeeb3
6 changed files with 289 additions and 8 deletions

View File

@ -41,6 +41,7 @@ import org.hibernate.envers.tools.Tools;
import org.hibernate.cfg.Configuration;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.CollectionEntry;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.event.AbstractCollectionEvent;
import org.hibernate.event.Initializable;
import org.hibernate.event.PostCollectionRecreateEvent;
@ -66,7 +67,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
private AuditConfiguration verCfg;
private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, EntityPersister entityPersister,
String entityName, Object[] newState, Object[] oldState) {
String entityName, Object[] newState, Object[] oldState,
SessionImplementor session) {
// Checking if this is enabled in configuration ...
if (!verCfg.getGlobalCfg().isGenerateRevisionsForCollections()) {
return;
@ -86,18 +88,26 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
Object newValue = newState == null ? null : newState[i];
if (!Tools.objectsEqual(oldValue, newValue)) {
IdMapper idMapper = verCfg.getEntCfg().get(relDesc.getToEntityName()).getIdMapper();
// We have to generate changes both in the old collection (size decreses) and new collection
// (size increases).
if (newValue != null) {
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
// of subclasses, this will be root class, no the actual class. So it can't be used here.
String toEntityName = session.guessEntityName(newValue);
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
Serializable id = (Serializable) idMapper.mapToIdFromEntity(newValue);
verSync.addWorkUnit(new CollectionChangeWorkUnit(relDesc.getToEntityName(), verCfg, id, newValue));
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, newValue));
}
if (oldValue != null) {
String toEntityName = session.guessEntityName(oldValue);
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
Serializable id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
verSync.addWorkUnit(new CollectionChangeWorkUnit(relDesc.getToEntityName(), verCfg, id, oldValue));
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, oldValue));
}
}
}
@ -113,7 +123,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
verSync.addWorkUnit(new AddWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
event.getPersister(), event.getState()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(), null);
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
null, event.getSession());
}
}
@ -126,7 +137,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
verSync.addWorkUnit(new ModWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
event.getPersister(), event.getState(), event.getOldState()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(), event.getOldState());
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
event.getOldState(), event.getSession());
}
}
@ -138,7 +150,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
verSync.addWorkUnit(new DelWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null, event.getDeletedState());
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null,
event.getDeletedState(), event.getSession());
}
}

View File

@ -0,0 +1,73 @@
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
import org.hibernate.envers.Audited;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
@Audited
public class Address implements Serializable {
@Id @GeneratedValue
private Long id;
private String address1;
@ManyToOne
private Contact contact;
public Address() {
}
public Address(Long id, String address1) {
this.id = id;
this.address1 = address1;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAddress1() {
return address1;
}
public void setAddress1(String address1) {
this.address1 = address1;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Address)) return false;
Address address = (Address) o;
if (address1 != null ? !address1.equals(address.address1) : address.address1 != null) return false;
if (id != null ? !id.equals(address.id) : address.id != null) return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (address1 != null ? address1.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,53 @@
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import org.hibernate.envers.Audited;
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("Contact")
@DiscriminatorColumn(name="contactType",discriminatorType=javax.persistence.DiscriminatorType.STRING)
@Audited
public class Contact implements Serializable {
@Id @GeneratedValue
private Long id;
private String email;
@OneToMany(mappedBy="contact")
private Set<Address> addresses;
public Contact() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<Address> getAddresses() {
return addresses;
}
public void setAddresses(Set<Address> addresses) {
this.addresses = addresses;
}
}

View File

@ -0,0 +1,120 @@
/*
* 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.inheritance.single.inheritedrelation;
import java.util.Arrays;
import javax.persistence.EntityManager;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.tools.TestTools;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.hibernate.ejb.Ejb3Configuration;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class InheritedBidirectional extends AbstractEntityTest {
private Long pc_id;
private Long a1_id;
private Long a2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(Address.class);
cfg.addAnnotatedClass(Contact.class);
cfg.addAnnotatedClass(PersonalContact.class);
}
@BeforeClass(dependsOnMethods = "init")
public void initData() {
EntityManager em = getEntityManager();
// Rev 1
em.getTransaction().begin();
PersonalContact pc = new PersonalContact();
pc.setEmail("e");
pc.setFirstname("f");
Address a1 = new Address();
a1.setAddress1("a1");
a1.setContact(pc);
em.persist(pc);
em.persist(a1);
em.getTransaction().commit();
// Rev 2
em.getTransaction().begin();
pc = em.find(PersonalContact.class, pc.getId());
Address a2 = new Address();
a2.setAddress1("a2");
a2.setContact(pc);
em.persist(a2);
em.getTransaction().commit();
//
pc_id = pc.getId();
a1_id = a1.getId();
a2_id = a2.getId();
}
@Test
public void testRevisionsCounts() {
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(Contact.class, pc_id));
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(PersonalContact.class, pc_id));
assert Arrays.asList(1).equals(getAuditReader().getRevisions(Address.class, a1_id));
assert Arrays.asList(1).equals(getAuditReader().getRevisions(Address.class, a1_id));
assert Arrays.asList(2).equals(getAuditReader().getRevisions(Address.class, a2_id));
assert Arrays.asList(2).equals(getAuditReader().getRevisions(Address.class, a2_id));
}
@Test
public void testHistoryOfContact() {
assert getAuditReader().find(Contact.class, pc_id, 1).getAddresses().equals(
TestTools.makeSet(new Address(a1_id, "a1")));
assert getAuditReader().find(Contact.class, pc_id, 2).getAddresses().equals(
TestTools.makeSet(new Address(a1_id, "a1"), new Address(a2_id, "a2")));
}
@Test
public void testHistoryOfPersonalContact() {
assert getAuditReader().find(PersonalContact.class, pc_id, 1).getAddresses().equals(
TestTools.makeSet(new Address(a1_id, "a1")));
assert getAuditReader().find(PersonalContact.class, pc_id, 2).getAddresses().equals(
TestTools.makeSet(new Address(a1_id, "a1"), new Address(a2_id, "a2")));
}
}

View File

@ -0,0 +1,21 @@
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import org.hibernate.envers.Audited;
@Entity
@DiscriminatorValue("PersonalContact")
@Audited
public class PersonalContact extends Contact {
private String firstname;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}

View File

@ -15,6 +15,7 @@
<package name="org.hibernate.envers.test.integration.ids" />
<package name="org.hibernate.envers.test.integration.inheritance.single" />
<package name="org.hibernate.envers.test.integration.inheritance.single.childrelation" />
<package name="org.hibernate.envers.test.integration.inheritance.single.inheritedrelation" />
<package name="org.hibernate.envers.test.integration.inheritance.single.relation" />
<package name="org.hibernate.envers.test.integration.manytomany" />
<package name="org.hibernate.envers.test.integration.manytomany.ternary" />