HHH-3871:

- not loading proxied objects when not necessary
- test

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16393 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Adam Warski 2009-04-22 08:38:05 +00:00
parent 0f9a6882b9
commit ac0889dbd6
21 changed files with 421 additions and 65 deletions

View File

@ -36,6 +36,7 @@ import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import org.hibernate.util.ReflectHelper;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -63,8 +64,8 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
delegate.addComposite(propertyData, propertyMapper);
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
return delegate.mapToMapFromEntity(data, newObj, oldObj);
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
return delegate.mapToMapFromEntity(session, data, newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {

View File

@ -23,11 +23,13 @@
*/
package org.hibernate.envers.entities.mapper;
import org.hibernate.engine.SessionImplementor;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
}

View File

@ -36,6 +36,7 @@ import org.hibernate.envers.tools.MappingTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Getter;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -75,13 +76,13 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
private Object getAtIndexOrNull(Object[] array, int index) { return array == null ? null : array[index]; }
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean ret = false;
for (int i=0; i<propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (propertyDatas.containsKey(propertyName)) {
ret |= properties.get(propertyDatas.get(propertyName)).mapToMapFromEntity(data,
ret |= properties.get(propertyDatas.get(propertyName)).mapToMapFromEntity(session, data,
getAtIndexOrNull(newState, i),
getAtIndexOrNull(oldState, i));
}
@ -90,7 +91,7 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
return ret;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
boolean ret = false;
for (PropertyData propertyData : properties.keySet()) {
Getter getter;
@ -102,7 +103,7 @@ public class MultiPropertyMapper implements ExtendedPropertyMapper {
return false;
}
ret |= properties.get(propertyData).mapToMapFromEntity(data,
ret |= properties.get(propertyData).mapToMapFromEntity(session, data,
newObj == null ? null : getter.get(newObj),
oldObj == null ? null : getter.get(oldObj));
}

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -38,12 +39,13 @@ import org.hibernate.collection.PersistentCollection;
public interface PropertyMapper {
/**
* Maps properties to the given map, basing on differences between properties of new and old objects.
* @param data Data to map to.
* @param newObj New state of the entity.
* @param oldObj Old state of the entity.
* @return True if there are any differences between the states represented by newObj and oldObj.
* @param session The current session.
* @param data Data to map to.
* @param newObj New state of the entity.
* @param oldObj Old state of the entity.
* @return True if there are any differences between the states represented by newObj and oldObj.
*/
boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj);
boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj);
/**
* Maps properties from the given map to the given object.

View File

@ -36,6 +36,7 @@ import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import org.hibernate.engine.SessionImplementor;
/**
* TODO: diff
@ -54,7 +55,7 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder
this.propertyData = propertyData;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
data.put(propertyData.getName(), newObj);
return !Tools.objectsEqual(newObj, oldObj);

View File

@ -32,6 +32,7 @@ import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionImplementor;
/**
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
@ -47,16 +48,16 @@ public class SubclassPropertyMapper implements ExtendedPropertyMapper {
this.parentMapper = parentMapper;
}
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean parentDiffs = parentMapper.map(data, propertyNames, newState, oldState);
boolean mainDiffs = main.map(data, propertyNames, newState, oldState);
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean parentDiffs = parentMapper.map(session, data, propertyNames, newState, oldState);
boolean mainDiffs = main.map(session, data, propertyNames, newState, oldState);
return parentDiffs || mainDiffs;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
boolean parentDiffs = parentMapper.mapToMapFromEntity(data, newObj, oldObj);
boolean mainDiffs = main.mapToMapFromEntity(data, newObj, oldObj);
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
boolean parentDiffs = parentMapper.mapToMapFromEntity(session, data, newObj, oldObj);
boolean mainDiffs = main.mapToMapFromEntity(session, data, newObj, oldObj);
return parentDiffs || mainDiffs;
}

View File

@ -45,6 +45,7 @@ import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -130,7 +131,7 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
return collectionChanges;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
// Changes are mapped in the "mapCollectionChanges" method.
return false;
}

View File

@ -38,6 +38,7 @@ import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.NonUniqueResultException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
@ -56,7 +57,7 @@ public class OneToOneNotOwningMapper implements PropertyMapper {
this.propertyData = propertyData;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
return false;
}

View File

@ -40,6 +40,7 @@ import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -55,13 +56,13 @@ public class ToOneIdMapper implements PropertyMapper {
this.referencedEntityName = referencedEntityName;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
HashMap<String, Object> newData = new HashMap<String, Object>();
data.put(propertyData.getName(), newData);
delegate.mapToMapFromEntity(newData, newObj);
return !Tools.objectsEqual(newObj, oldObj);
return !Tools.entitiesEqual(session, newObj, oldObj);
}
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,

View File

@ -90,41 +90,49 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
Object oldValue = oldState == null ? null : oldState[i];
Object newValue = newState == null ? null : newState[i];
if (!Tools.objectsEqual(oldValue, newValue)) {
if (!Tools.entitiesEqual(session, oldValue, newValue)) {
// 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;
if(newValue instanceof HibernateProxy) {
Serializable id;
if (newValue instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) newValue;
toEntityName = session.bestGuessEntityName(newValue);
newValue = hibernateProxy.getHibernateLazyInitializer().getImplementation();
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
// We've got to initialize the object from the proxy to later read its state.
newValue = Tools.getTargetFromProxy(hibernateProxy);
} else {
toEntityName = session.guessEntityName(newValue);
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(newValue);
}
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
Serializable id = (Serializable) idMapper.mapToIdFromEntity(newValue);
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, newValue));
verSync.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, newValue));
}
if (oldValue != null) {
String toEntityName;
Serializable id;
if(oldValue instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) oldValue;
toEntityName = session.bestGuessEntityName(oldValue);
oldValue = hibernateProxy.getHibernateLazyInitializer().getImplementation();
id = hibernateProxy.getHibernateLazyInitializer().getIdentifier();
// We've got to initialize the object as we'll read it's state anyway.
oldValue = Tools.getTargetFromProxy(hibernateProxy);
} else {
toEntityName = session.guessEntityName(oldValue);
}
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
Serializable id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, oldValue));
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
}
verSync.addWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, verCfg, id, oldValue));
}
}
}
@ -137,8 +145,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
if (verCfg.getEntCfg().isVersioned(entityName)) {
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
verSync.addWorkUnit(new AddWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
event.getPersister(), event.getState()));
verSync.addWorkUnit(new AddWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId(), event.getPersister(), event.getState()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
null, event.getSession());
@ -151,8 +159,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
if (verCfg.getEntCfg().isVersioned(entityName)) {
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
verSync.addWorkUnit(new ModWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
event.getPersister(), event.getState(), event.getOldState()));
verSync.addWorkUnit(new ModWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId(), event.getPersister(), event.getState(), event.getOldState()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
event.getOldState(), event.getSession());
@ -165,7 +173,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
if (verCfg.getEntCfg().isVersioned(entityName)) {
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
verSync.addWorkUnit(new DelWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId()));
verSync.addWorkUnit(new DelWorkUnit(event.getSession(), event.getPersister().getEntityName(), verCfg,
event.getId()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null,
event.getDeletedState(), event.getSession());
@ -193,7 +202,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
Object relatedObj = changeData.getChangedElement();
Serializable relatedId = (Serializable) relatedIdMapper.mapToIdFromEntity(relatedObj);
verSync.addWorkUnit(new CollectionChangeWorkUnit(relatedEntityName, verCfg, relatedId, relatedObj));
verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), relatedEntityName, verCfg,
relatedId, relatedObj));
}
}
}
@ -205,14 +215,14 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
if (verCfg.getEntCfg().isVersioned(entityName)) {
AuditSync verSync = verCfg.getSyncManager().get(event.getSession());
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(entityName, verCfg,
newColl, collectionEntry, oldColl, event.getAffectedOwnerIdOrNull());
PersistentCollectionChangeWorkUnit workUnit = new PersistentCollectionChangeWorkUnit(event.getSession(),
entityName, verCfg, newColl, collectionEntry, oldColl, event.getAffectedOwnerIdOrNull());
verSync.addWorkUnit(workUnit);
if (workUnit.containsWork()) {
// There are some changes: a revision needs also be generated for the collection owner
verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getAffectedOwnerEntityName(), verCfg,
event.getAffectedOwnerIdOrNull(), event.getAffectedOwnerOrNull()));
verSync.addWorkUnit(new CollectionChangeWorkUnit(event.getSession(), event.getAffectedOwnerEntityName(),
verCfg, event.getAffectedOwnerIdOrNull(), event.getAffectedOwnerOrNull()));
generateBidirectionalCollectionChangeWorkUnits(verSync, event, workUnit);
}

View File

@ -32,11 +32,13 @@ import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractAuditWorkUnit implements AuditWorkUnit {
protected final SessionImplementor sessionImplementor;
protected final AuditConfiguration verCfg;
protected final Serializable id;
@ -44,7 +46,9 @@ public abstract class AbstractAuditWorkUnit implements AuditWorkUnit {
private Object performedData;
protected AbstractAuditWorkUnit(String entityName, AuditConfiguration verCfg, Serializable id) {
protected AbstractAuditWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id) {
this.sessionImplementor = sessionImplementor;
this.verCfg = verCfg;
this.id = id;
this.entityName = entityName;

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@ -40,9 +41,9 @@ public class AddWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
private final Object[] state;
private final String[] propertyNames;
public AddWorkUnit(String entityName, AuditConfiguration verCfg, Serializable id,
EntityPersister entityPersister, Object[] state) {
super(entityName, verCfg, id);
public AddWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, EntityPersister entityPersister, Object[] state) {
super(sessionImplementor, entityName, verCfg, id);
this.state = state;
this.propertyNames = entityPersister.getPropertyNames();
@ -56,7 +57,8 @@ public class AddWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
Map<String, Object> data = new HashMap<String, Object>();
fillDataWithId(data, revisionData, RevisionType.ADD);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(data, propertyNames, state, null);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(sessionImplementor, data,
propertyNames, state, null);
session.save(verCfg.getAuditEntCfg().getAuditEntityName(getEntityName()), data);

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -38,8 +39,9 @@ import org.hibernate.Session;
public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit {
private final Object entity;
public CollectionChangeWorkUnit(String entityName, AuditConfiguration verCfg, Serializable id, Object entity) {
super(entityName, verCfg, id);
public CollectionChangeWorkUnit(SessionImplementor session, String entityName, AuditConfiguration verCfg,
Serializable id, Object entity) {
super(session, entityName, verCfg, id);
this.entity = entity;
}
@ -52,7 +54,8 @@ public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements A
Map<String, Object> data = new HashMap<String, Object>();
fillDataWithId(data, revisionData, RevisionType.MOD);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().mapToMapFromEntity(data, entity, null);
verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().mapToMapFromEntity(sessionImplementor,
data, entity, null);
session.save(verCfg.getAuditEntCfg().getAuditEntityName(getEntityName()), data);

View File

@ -31,13 +31,14 @@ import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class DelWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit {
public DelWorkUnit(String entityName, AuditConfiguration verCfg, Serializable id) {
super(entityName, verCfg, id);
public DelWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Serializable id) {
super(sessionImplementor, entityName, verCfg, id);
}
public boolean containsWork() {

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@ -40,13 +41,13 @@ public class ModWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
private final Map<String, Object> data;
private final boolean changes;
public ModWorkUnit(String entityName, AuditConfiguration verCfg, Serializable id,
EntityPersister entityPersister, Object[] newState, Object[] oldState) {
super(entityName, verCfg, id);
public ModWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, EntityPersister entityPersister, Object[] newState, Object[] oldState) {
super(sessionImplementor, entityName, verCfg, id);
data = new HashMap<String, Object>();
changes = verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(data, entityPersister.getPropertyNames(),
newState, oldState);
changes = verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(sessionImplementor, data,
entityPersister.getPropertyNames(), newState, oldState);
}
public boolean containsWork() {

View File

@ -34,6 +34,7 @@ import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.Session;
import org.hibernate.persister.collection.AbstractCollectionPersister;
import org.hibernate.engine.CollectionEntry;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.collection.PersistentCollection;
/**
@ -43,10 +44,10 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
private final List<PersistentCollectionChangeData> collectionChanges;
private final String referencingPropertyName;
public PersistentCollectionChangeWorkUnit(String entityName, AuditConfiguration verCfg,
PersistentCollection collection, CollectionEntry collectionEntry,
Serializable snapshot, Serializable id) {
super(entityName, verCfg, null);
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
AuditConfiguration verCfg, PersistentCollection collection,
CollectionEntry collectionEntry, Serializable snapshot, Serializable id) {
super(sessionImplementor, entityName, verCfg, null);
String ownerEntityName = ((AbstractCollectionPersister) collectionEntry.getLoadedPersister()).getOwnerEntityName();
referencingPropertyName = collectionEntry.getRole().substring(ownerEntityName.length() + 1);

View File

@ -23,6 +23,10 @@
*/
package org.hibernate.envers.tools;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.Session;
import java.util.*;
/**
@ -41,6 +45,42 @@ public class Tools {
return new LinkedHashMap<K,V>();
}
public static boolean entitiesEqual(SessionImplementor session, Object obj1, Object obj2) {
Object id1 = getIdentifier(session, obj1);
Object id2 = getIdentifier(session, obj2);
return objectsEqual(id1, id2);
}
public static Object getIdentifier(SessionImplementor session, Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof HibernateProxy) {
HibernateProxy hibernateProxy = (HibernateProxy) obj;
return hibernateProxy.getHibernateLazyInitializer().getIdentifier();
}
return session.getEntityPersister(null, obj).getIdentifier(obj, session.getEntityMode());
}
public static Object getTargetFromProxy(HibernateProxy proxy) {
if (!proxy.getHibernateLazyInitializer().isUninitialized()) {
return proxy.getHibernateLazyInitializer().getImplementation();
}
Session tempSession = proxy.getHibernateLazyInitializer().getSession().getFactory().openTemporarySession();
try {
proxy.getHibernateLazyInitializer().setSession((SessionImplementor) tempSession);
proxy.getHibernateLazyInitializer().initialize();
return proxy.getHibernateLazyInitializer().getImplementation();
} finally {
tempSession.close();
}
}
public static boolean objectsEqual(Object obj1, Object obj2) {
if (obj1 == null) {
return obj2 == null;

View File

@ -0,0 +1,150 @@
/*
* 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.reference;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.tools.TestTools;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import javax.persistence.EntityManager;
import java.util.Arrays;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class BidirectionalReference extends AbstractEntityTest {
private Long set1_id;
private Long set2_id;
private Long g1_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(GreetingPO.class);
cfg.addAnnotatedClass(GreetingSetPO.class);
}
@BeforeClass(dependsOnMethods = "init")
public void initData() {
EntityManager em = getEntityManager();
GreetingSetPO set1 = new GreetingSetPO();
set1.setName("a1");
GreetingSetPO set2 = new GreetingSetPO();
set2.setName("a2");
// Revision 1
em.getTransaction().begin();
em.persist(set1);
em.persist(set2);
set1_id = set1.getId();
set2_id = set2.getId();
em.getTransaction().commit();
em.clear();
// Revision 2
em.getTransaction().begin();
GreetingPO g1 = new GreetingPO();
g1.setGreeting("g1");
g1.setGreetingSet(em.getReference(GreetingSetPO.class, set1_id));
em.persist(g1);
g1_id = g1.getId();
em.getTransaction().commit();
em.clear();
// Revision 3
em.getTransaction().begin();
g1 = em.find(GreetingPO.class, g1_id);
g1.setGreetingSet(em.getReference(GreetingSetPO.class, set2_id));
em.getTransaction().commit();
}
@Test
public void testRevisionsCounts() {
assert Arrays.asList(2, 3).equals(getAuditReader().getRevisions(GreetingPO.class, g1_id));
assert Arrays.asList(1, 2, 3).equals(getAuditReader().getRevisions(GreetingSetPO.class, set1_id));
assert Arrays.asList(1, 3).equals(getAuditReader().getRevisions(GreetingSetPO.class, set2_id));
}
@Test
public void testHistoryOfG1() {
GreetingPO rev1 = getAuditReader().find(GreetingPO.class, g1_id, 1);
GreetingPO rev2 = getAuditReader().find(GreetingPO.class, g1_id, 2);
GreetingPO rev3 = getAuditReader().find(GreetingPO.class, g1_id, 3);
assert rev1 == null;
assert rev2.getGreetingSet().getName().equals("a1");
assert rev3.getGreetingSet().getName().equals("a2");
}
@Test
public void testHistoryOfSet1() {
GreetingSetPO rev1 = getAuditReader().find(GreetingSetPO.class, set1_id, 1);
GreetingSetPO rev2 = getAuditReader().find(GreetingSetPO.class, set1_id, 2);
GreetingSetPO rev3 = getAuditReader().find(GreetingSetPO.class, set1_id, 3);
assert rev1.getName().equals("a1");
assert rev2.getName().equals("a1");
assert rev3.getName().equals("a1");
GreetingPO g1 = new GreetingPO();
g1.setId(g1_id);
g1.setGreeting("g1");
assert rev1.getGreetings().size() == 0;
assert rev2.getGreetings().equals(TestTools.makeSet(g1));
assert rev3.getGreetings().size() == 0;
}
@Test
public void testHistoryOfSet2() {
GreetingSetPO rev1 = getAuditReader().find(GreetingSetPO.class, set2_id, 1);
GreetingSetPO rev2 = getAuditReader().find(GreetingSetPO.class, set2_id, 2);
GreetingSetPO rev3 = getAuditReader().find(GreetingSetPO.class, set2_id, 3);
assert rev1.getName().equals("a2");
assert rev2.getName().equals("a2");
assert rev3.getName().equals("a2");
GreetingPO g1 = new GreetingPO();
g1.setId(g1_id);
g1.setGreeting("g1");
assert rev1.getGreetings().size() == 0;
assert rev2.getGreetings().size() == 0;
assert rev3.getGreetings().equals(TestTools.makeSet(g1));
}
}

View File

@ -0,0 +1,65 @@
package org.hibernate.envers.test.integration.reference;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.hibernate.envers.Audited;
@Entity
@Audited
public class GreetingPO {
@Id
@GeneratedValue
private Long id;
private String theGreeting;
@ManyToOne
private GreetingSetPO greetingSet;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getGreeting() {
return theGreeting;
}
public void setGreeting(String greeting) {
this.theGreeting = greeting;
}
public GreetingSetPO getGreetingSet() {
return greetingSet;
}
public void setGreetingSet(GreetingSetPO greetingSet) {
this.greetingSet = greetingSet;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GreetingPO)) return false;
GreetingPO that = (GreetingPO) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (theGreeting != null ? !theGreeting.equals(that.theGreeting) : that.theGreeting != null) return false;
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (theGreeting != null ? theGreeting.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,67 @@
package org.hibernate.envers.test.integration.reference;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.hibernate.envers.Audited;
@Entity
@Audited
public class GreetingSetPO {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "greetingSet")
private Set<GreetingPO> greetings;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<GreetingPO> getGreetings() {
return greetings;
}
public void setGreetings(Set<GreetingPO> greetings) {
this.greetings = greetings;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GreetingSetPO)) return false;
GreetingSetPO that = (GreetingSetPO) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}

View File

@ -45,6 +45,7 @@
<package name="org.hibernate.envers.test.integration.properties" />
<package name="org.hibernate.envers.test.integration.query" />
<package name="org.hibernate.envers.test.integration.query.ids" />
<package name="org.hibernate.envers.test.integration.reference" />
<package name="org.hibernate.envers.test.integration.reventity" />
<package name="org.hibernate.envers.test.integration.revfordate" />
<package name="org.hibernate.envers.test.integration.sameids" />