HHH-6825 - ToOne property mappers refactoring
This commit is contained in:
parent
5c80268664
commit
c703d134f2
|
@ -133,8 +133,8 @@ public final class ToOneRelationMetadataGenerator {
|
|||
|
||||
// Adding mapper for the id
|
||||
PropertyData propertyData = propertyAuditingData.getPropertyData();
|
||||
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(owningReferencePropertyName,
|
||||
referencedEntityName, propertyData));
|
||||
mapper.addComposite(propertyData, new OneToOneNotOwningMapper(entityName, referencedEntityName,
|
||||
owningReferencePropertyName, propertyData));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.hibernate.envers.entities.mapper.relation;
|
||||
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
import org.hibernate.envers.exception.AuditException;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Template class for property mappers that represent one-to-one relation.
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public abstract class AbstractOneToOneMapper extends AbstractToOneMapper {
|
||||
private final String entityName;
|
||||
private final String referencedEntityName;
|
||||
|
||||
protected AbstractOneToOneMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
||||
super(propertyData);
|
||||
this.entityName = entityName;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
}
|
||||
|
||||
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
RelationDescriptor relation = getRelationDescriptor(verCfg, referencedEntityName);
|
||||
|
||||
Object value = null;
|
||||
try {
|
||||
value = queryForReferencedEntity(versionsReader, relation, (Serializable) primaryKey, revision);
|
||||
} catch (NoResultException e) {
|
||||
value = null;
|
||||
} catch (NonUniqueResultException e) {
|
||||
throw new AuditException("Many versions results for one-to-one relationship " + entityName +
|
||||
"." + getPropertyData().getBeanName() + ".", e);
|
||||
}
|
||||
|
||||
setPropertyValue(obj, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param versionsReader Audit reader.
|
||||
* @param relation Relation descriptor.
|
||||
* @param primaryKey Related entity identifier.
|
||||
* @param revision Revision number.
|
||||
* @return Referenced object or proxy of one-to-one relation.
|
||||
*/
|
||||
protected abstract Object queryForReferencedEntity(AuditReaderImplementor versionsReader, RelationDescriptor relation,
|
||||
Serializable primaryKey, Number revision);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.hibernate.envers.entities.mapper.relation;
|
||||
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.EntityConfiguration;
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||
import org.hibernate.property.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for property mappers that represent to-one relation.
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public abstract class AbstractToOneMapper implements PropertyMapper {
|
||||
private final PropertyData propertyData;
|
||||
|
||||
protected AbstractToOneMapper(PropertyData propertyData) {
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
if (obj != null) {
|
||||
nullSafeMapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl, Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param verCfg Audit configuration.
|
||||
* @param entityName Entity name.
|
||||
* @return Entity class, name and information whether it is audited or not.
|
||||
*/
|
||||
protected RelationDescriptor getRelationDescriptor(AuditConfiguration verCfg, String entityName) {
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(entityName);
|
||||
boolean isRelationAudited = true;
|
||||
if (entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(entityName);
|
||||
isRelationAudited = false;
|
||||
}
|
||||
Class entityClass = ReflectionTools.loadClass(entCfg.getEntityClassName());
|
||||
return new RelationDescriptor(entityClass, entityName, isRelationAudited);
|
||||
}
|
||||
|
||||
protected void setPropertyValue(Object targetObject, Object value) {
|
||||
Setter setter = ReflectionTools.getSetter(targetObject.getClass(), propertyData);
|
||||
setter.set(targetObject, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Bean property that represents the relation.
|
||||
*/
|
||||
protected PropertyData getPropertyData() {
|
||||
return propertyData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter {@code obj} is never {@code null}.
|
||||
* @see PropertyMapper#mapToEntityFromMap(AuditConfiguration, Object, Map, Object, AuditReaderImplementor, Number)
|
||||
*/
|
||||
public abstract void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision);
|
||||
|
||||
/**
|
||||
* Simple descriptor of managed relation.
|
||||
*/
|
||||
protected class RelationDescriptor {
|
||||
private final Class referencedEntityClass;
|
||||
private final String referencedEntityName;
|
||||
private final boolean audited;
|
||||
|
||||
public RelationDescriptor(Class referencedEntityClass, String referencedEntityName, boolean audited) {
|
||||
this.referencedEntityClass = referencedEntityClass;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
this.audited = audited;
|
||||
}
|
||||
|
||||
public Class getReferencedEntityClass() { return referencedEntityClass; }
|
||||
public String getReferencedEntityName() { return referencedEntityName; }
|
||||
public boolean isAudited() { return audited; }
|
||||
}
|
||||
}
|
|
@ -22,78 +22,35 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.envers.entities.mapper.relation;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.NoResultException;
|
||||
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.EntityConfiguration;
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.exception.AuditException;
|
||||
import org.hibernate.envers.query.AuditEntity;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||
import org.hibernate.property.Setter;
|
||||
|
||||
import javax.persistence.OneToOne;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Property mapper for not owning side of {@link OneToOne} relation.
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hern<EFBFBD>n Chanfreau
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class OneToOneNotOwningMapper implements PropertyMapper {
|
||||
private String owningReferencePropertyName;
|
||||
private String owningEntityName;
|
||||
private PropertyData propertyData;
|
||||
public class OneToOneNotOwningMapper extends AbstractOneToOneMapper {
|
||||
private final String owningReferencePropertyName;
|
||||
|
||||
public OneToOneNotOwningMapper(String owningReferencePropertyName, String owningEntityName,
|
||||
public OneToOneNotOwningMapper(String notOwningEntityName, String owningEntityName, String owningReferencePropertyName,
|
||||
PropertyData propertyData) {
|
||||
super(notOwningEntityName, owningEntityName, propertyData);
|
||||
this.owningReferencePropertyName = owningReferencePropertyName;
|
||||
this.owningEntityName = owningEntityName;
|
||||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(owningEntityName);
|
||||
if(entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(owningEntityName);
|
||||
}
|
||||
|
||||
Class<?> entityClass = ReflectionTools.loadClass(entCfg.getEntityClassName());
|
||||
|
||||
Object value;
|
||||
|
||||
try {
|
||||
value = versionsReader.createQuery().forEntitiesAtRevision(entityClass, owningEntityName, revision)
|
||||
.add(AuditEntity.relatedId(owningReferencePropertyName).eq(primaryKey)).getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
value = null;
|
||||
} catch (NonUniqueResultException e) {
|
||||
throw new AuditException("Many versions results for one-to-one relationship: (" + owningEntityName +
|
||||
", " + owningReferencePropertyName + ")");
|
||||
}
|
||||
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
||||
setter.set(obj, value, null);
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
@Override
|
||||
protected Object queryForReferencedEntity(AuditReaderImplementor versionsReader, RelationDescriptor relation,
|
||||
Serializable primaryKey, Number revision) {
|
||||
return versionsReader.createQuery().forEntitiesAtRevision(relation.getReferencedEntityClass(),
|
||||
relation.getReferencedEntityName(), revision)
|
||||
.add(AuditEntity.relatedId(owningReferencePropertyName).eq(primaryKey))
|
||||
.getSingleResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +1,38 @@
|
|||
package org.hibernate.envers.entities.mapper.relation;
|
||||
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.EntityConfiguration;
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.exception.AuditException;
|
||||
import org.hibernate.envers.query.AuditEntity;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.property.Setter;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Property mapper for {@link OneToOne} with {@link PrimaryKeyJoinColumn} relation.
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public class OneToOnePrimaryKeyJoinColumnMapper implements PropertyMapper {
|
||||
private final String entityName;
|
||||
private final String referencedEntityName;
|
||||
private final PropertyData propertyData;
|
||||
|
||||
public class OneToOnePrimaryKeyJoinColumnMapper extends AbstractOneToOneMapper {
|
||||
public OneToOnePrimaryKeyJoinColumnMapper(String entityName, String referencedEntityName, PropertyData propertyData) {
|
||||
this.entityName = entityName;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
this.propertyData = propertyData;
|
||||
super(entityName, referencedEntityName, propertyData);
|
||||
}
|
||||
|
||||
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj, Object oldObj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey, AuditReaderImplementor versionsReader, Number revision) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
@Override
|
||||
protected Object queryForReferencedEntity(AuditReaderImplementor versionsReader, RelationDescriptor relation,
|
||||
Serializable primaryKey, Number revision) {
|
||||
if (relation.isAudited()) {
|
||||
// Audited relation.
|
||||
return versionsReader.createQuery().forEntitiesAtRevision(relation.getReferencedEntityClass(),
|
||||
relation.getReferencedEntityName(), revision)
|
||||
.add(AuditEntity.id().eq(primaryKey))
|
||||
.getSingleResult();
|
||||
} else {
|
||||
// Not audited relation.
|
||||
return createNotAuditedEntityReference(versionsReader, relation.getReferencedEntityClass(),
|
||||
relation.getReferencedEntityName(), primaryKey);
|
||||
}
|
||||
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(referencedEntityName);
|
||||
boolean isRelationAudited = true;
|
||||
if (entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(referencedEntityName);
|
||||
isRelationAudited = false;
|
||||
}
|
||||
|
||||
Class<?> entityClass = ReflectionTools.loadClass(entCfg.getEntityClassName());
|
||||
Object value = null;
|
||||
try {
|
||||
if (isRelationAudited) {
|
||||
value = versionsReader.createQuery().forEntitiesAtRevision(entityClass, referencedEntityName, revision)
|
||||
.add(AuditEntity.id().eq(primaryKey)).getSingleResult();
|
||||
} else {
|
||||
value = createNotAuditedEntityReference(versionsReader, entityClass, referencedEntityName,
|
||||
(Serializable) primaryKey);
|
||||
}
|
||||
} catch (NoResultException e) {
|
||||
value = null;
|
||||
} catch (NonUniqueResultException e) {
|
||||
throw new AuditException("Many versions results for one-to-one relationship: (" + entityName +
|
||||
", " + propertyData.getBeanName() + ")");
|
||||
}
|
||||
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
||||
setter.set(obj, value, null);
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +41,7 @@ public class OneToOnePrimaryKeyJoinColumnMapper implements PropertyMapper {
|
|||
* of an entity.
|
||||
*/
|
||||
private Object createNotAuditedEntityReference(AuditReaderImplementor versionsReader, Class<?> entityClass,
|
||||
String entityName, Serializable primaryKey) {
|
||||
String entityName, Serializable primaryKey) {
|
||||
EntityPersister entityPersister = versionsReader.getSessionImplementor().getFactory().getEntityPersister(entityName);
|
||||
if (entityPersister.hasProxy()) {
|
||||
// If possible create a proxy. Returning complete object may affect performance.
|
||||
|
|
|
@ -25,36 +25,28 @@ package org.hibernate.envers.entities.mapper.relation;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.entities.EntityConfiguration;
|
||||
import org.hibernate.envers.entities.PropertyData;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.Tools;
|
||||
import org.hibernate.envers.tools.reflection.ReflectionTools;
|
||||
import org.hibernate.property.Setter;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hern<EFBFBD>n Chanfreau
|
||||
*/
|
||||
public class ToOneIdMapper implements PropertyMapper {
|
||||
public class ToOneIdMapper extends AbstractToOneMapper {
|
||||
private final IdMapper delegate;
|
||||
private final PropertyData propertyData;
|
||||
private final String referencedEntityName;
|
||||
private final boolean nonInsertableFake;
|
||||
|
||||
public ToOneIdMapper(IdMapper delegate, PropertyData propertyData, String referencedEntityName, boolean nonInsertableFake) {
|
||||
super(propertyData);
|
||||
this.delegate = delegate;
|
||||
this.propertyData = propertyData;
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
this.nonInsertableFake = nonInsertableFake;
|
||||
}
|
||||
|
@ -75,42 +67,22 @@ public class ToOneIdMapper implements PropertyMapper {
|
|||
return nonInsertableFake ? false : !Tools.entitiesEqual(session, referencedEntityName, newObj, oldObj);
|
||||
}
|
||||
|
||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object entityId;
|
||||
entityId = delegate.mapToIdFromMap(data);
|
||||
Object value;
|
||||
if (entityId == null) {
|
||||
value = null;
|
||||
} else {
|
||||
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||
AuditReaderImplementor versionsReader, Number revision) {
|
||||
Object entityId = delegate.mapToIdFromMap(data);
|
||||
Object value = null;
|
||||
if (entityId != null) {
|
||||
if (versionsReader.getFirstLevelCache().contains(referencedEntityName, revision, entityId)) {
|
||||
value = versionsReader.getFirstLevelCache().get(referencedEntityName, revision, entityId);
|
||||
} else {
|
||||
EntityConfiguration entCfg = verCfg.getEntCfg().get(referencedEntityName);
|
||||
if(entCfg == null) {
|
||||
// a relation marked as RelationTargetAuditMode.NOT_AUDITED
|
||||
entCfg = verCfg.getEntCfg().getNotVersionEntityConfiguration(referencedEntityName);
|
||||
}
|
||||
|
||||
Class<?> entityClass = ReflectionTools.loadClass(entCfg.getEntityClassName());
|
||||
RelationDescriptor relationDescriptor = getRelationDescriptor(verCfg, referencedEntityName);
|
||||
|
||||
value = versionsReader.getSessionImplementor().getFactory().getEntityPersister(referencedEntityName).
|
||||
createProxy((Serializable)entityId, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision, verCfg));
|
||||
createProxy((Serializable)entityId, new ToOneDelegateSessionImplementor(versionsReader, relationDescriptor.getReferencedEntityClass(),
|
||||
entityId, revision, verCfg));
|
||||
}
|
||||
}
|
||||
|
||||
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData);
|
||||
setter.set(obj, value, null);
|
||||
}
|
||||
|
||||
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
|
||||
PersistentCollection newColl,
|
||||
Serializable oldColl,
|
||||
Serializable id) {
|
||||
return null;
|
||||
setPropertyValue(obj, value);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue