Browse files

[HHH-6613] Added support for @ElementCollection of @Embeddable

  • Loading branch information...
1 parent b42d5f7 commit 936c93fec88f002bb4afa78245f71c93ebdd6791 @kristofferlundberg committed Oct 13, 2011
Showing with 1,438 additions and 132 deletions.
  1. +21 −0 hibernate-envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
  2. +3 −3 ...nate-envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
  3. +76 −21 ...envers/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
  4. +8 −5 ...rnate-envers/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
  5. +4 −0 ...ers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesHolder.java
  6. +4 −4 ...ers/src/main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
  7. +4 −0 ...nvers/src/main/java/org/hibernate/envers/configuration/metadata/reader/ComponentAuditingData.java
  8. +8 −0 hibernate-envers/src/main/java/org/hibernate/envers/entities/EntityInstantiator.java
  9. +5 −2 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/ComponentPropertyMapper.java
  10. +3 −0 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/CompositeMapperBuilder.java
  11. +2 −0 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/ExtendedPropertyMapper.java
  12. +10 −4 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/MultiPropertyMapper.java
  13. +2 −1 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/PropertyMapper.java
  14. +3 −2 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java
  15. +17 −3 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/SubclassPropertyMapper.java
  16. +46 −11 ...-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/AbstractCollectionMapper.java
  17. +10 −4 ...ate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/BasicCollectionMapper.java
  18. +27 −0 ...-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/CollectionPropertyMapper.java
  19. +11 −5 ...nate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ListCollectionMapper.java
  20. +11 −5 ...rnate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/MapCollectionMapper.java
  21. +3 −1 ...e-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/OneToOneNotOwningMapper.java
  22. +3 −2 ...envers/src/main/java/org/hibernate/envers/entities/mapper/relation/SortedMapCollectionMapper.java
  23. +3 −2 ...envers/src/main/java/org/hibernate/envers/entities/mapper/relation/SortedSetCollectionMapper.java
  24. +2 −1 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java
  25. +19 −2 .../src/main/java/org/hibernate/envers/entities/mapper/relation/component/MiddleComponentMapper.java
  26. +7 −2 ...main/java/org/hibernate/envers/entities/mapper/relation/component/MiddleDummyComponentMapper.java
  27. +113 −0 ...java/org/hibernate/envers/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java
  28. +7 −2 ...n/java/org/hibernate/envers/entities/mapper/relation/component/MiddleMapKeyIdComponentMapper.java
  29. +7 −2 .../org/hibernate/envers/entities/mapper/relation/component/MiddleMapKeyPropertyComponentMapper.java
  30. +9 −4 ...in/java/org/hibernate/envers/entities/mapper/relation/component/MiddleRelatedComponentMapper.java
  31. +10 −4 ...ain/java/org/hibernate/envers/entities/mapper/relation/component/MiddleSimpleComponentMapper.java
  32. +9 −4 ...n/java/org/hibernate/envers/entities/mapper/relation/component/MiddleStraightComponentMapper.java
  33. +4 −2 ...rs/src/main/java/org/hibernate/envers/entities/mapper/relation/query/OneEntityQueryGenerator.java
  34. +6 −4 .../src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
  35. +4 −2 ...n/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
  36. +5 −3 ...rs/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
  37. +1 −1 hibernate-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
  38. +17 −13 hibernate-envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
  39. +3 −3 hibernate-envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
  40. +24 −6 hibernate-envers/src/main/java/org/hibernate/envers/strategy/ValidityAuditStrategy.java
  41. +2 −2 ...s/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
  42. +91 −0 ...te-envers/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableListEntity.java
  43. +88 −0 ...ate-envers/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableMapEntity.java
  44. +89 −0 ...ate-envers/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableSetEntity.java
  45. +128 −0 hibernate-envers/src/matrix/java/org/hibernate/envers/test/entities/components/Component3.java
  46. +118 −0 hibernate-envers/src/matrix/java/org/hibernate/envers/test/entities/components/Component4.java
  47. +125 −0 ...rnate-envers/src/matrix/java/org/hibernate/envers/test/integration/collection/EmbeddableList.java
  48. +142 −0 hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/collection/EmbeddableMap.java
  49. +124 −0 hibernate-envers/src/matrix/java/org/hibernate/envers/test/integration/collection/EmbeddableSet.java
View
21 ...e-envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
@@ -58,6 +58,9 @@
private final boolean revisionEndTimestampEnabled;
private final String revisionEndTimestampFieldName;
+ private final String embeddableSetOrdinalPropertyName;
+ private final String embeddableSetOrdinalPropertyType;
+
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
this.revisionInfoEntityName = revisionInfoEntityName;
@@ -112,6 +115,16 @@ public AuditEntitiesConfiguration(Properties properties, String revisionInfoEnti
revisionNumberPath = originalIdPropName + "." + revisionFieldName + ".id";
revisionPropBasePath = originalIdPropName + "." + revisionFieldName + ".";
+
+ embeddableSetOrdinalPropertyName = getProperty(properties,
+ "org.hibernate.envers.embeddable_set_ordinal_field_name",
+ "org.hibernate.envers.embeddable_set_ordinal_field_name",
+ "SETORDINAL");
+
+ embeddableSetOrdinalPropertyType = getProperty(properties,
+ "org.hibernate.envers.embeddable_set_ordinal_field_type",
+ "org.hibernate.envers.embeddable_set_ordinal_field_type",
+ "integer");
}
public String getOriginalIdPropName() {
@@ -182,4 +195,12 @@ public String getAuditStrategyName() {
public String getRevisionEndFieldName() {
return revisionEndFieldName;
}
+
+ public String getEmbeddableSetOrdinalPropertyName() {
+ return embeddableSetOrdinalPropertyName;
+ }
+
+ public String getEmbeddableSetOrdinalPropertyType() {
+ return embeddableSetOrdinalPropertyType;
+ }
}
View
6 ...ers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
@@ -138,13 +138,13 @@ void addRevisionInfoRelation(Element any_mapping) {
any_mapping.add(cloneAndSetupRevisionInfoRelationMapping());
}
- void addRevisionType(Element any_mapping) {
+ void addRevisionType(Element any_mapping, Element any_mapping_end) {
Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(), true, false);
revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType");
// Adding the end revision, if appropriate
- addEndRevision(any_mapping);
+ addEndRevision(any_mapping_end);
}
private void addEndRevision(Element any_mapping ) {
@@ -343,7 +343,7 @@ private void addJoins(PersistentClass pc, CompositeMapperBuilder currentMapper,
class_mapping.add((Element) idMapper.getXmlMapping().clone());
// Adding the "revision type" property
- addRevisionType(class_mapping);
+ addRevisionType(class_mapping, class_mapping);
return Triple.make(class_mapping, propertyMapper, null);
}
View
97 ...rc/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
@@ -38,13 +38,17 @@
import org.jboss.logging.Logger;
import org.hibernate.MappingException;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode;
+import org.hibernate.envers.configuration.metadata.reader.AuditedPropertiesReader;
+import org.hibernate.envers.configuration.metadata.reader.ComponentAuditingData;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
+import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.SinglePropertyMapper;
import org.hibernate.envers.entities.mapper.id.IdMapper;
@@ -58,6 +62,7 @@
import org.hibernate.envers.entities.mapper.relation.SortedSetCollectionMapper;
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleDummyComponentMapper;
+import org.hibernate.envers.entities.mapper.relation.component.MiddleEmbeddableComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyIdComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyPropertyComponentMapper;
import org.hibernate.envers.entities.mapper.relation.component.MiddleRelatedComponentMapper;
@@ -75,13 +80,16 @@
import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Tools;
import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Component;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.type.BagType;
+import org.hibernate.type.ComponentType;
import org.hibernate.type.ListType;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.MapType;
@@ -348,7 +356,7 @@ private void addWithMiddleTable() {
// a query generator to read the raw data collection from the middle table.
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData,
- auditMiddleEntityName);
+ auditMiddleEntityName, isEmbeddableElementType());
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
if (middleEntityXml != null) {
@@ -461,52 +469,92 @@ private MiddleComponentData addValueToMiddleTable(Value value, Element xmlMappin
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
queryGeneratorBuilder.getCurrentIndex());
} else {
- // Last but one parameter: collection components are always insertable
- boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
- new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false),
- value, null, true, true);
-
- if (mapped) {
- // Simple values are always stored in the first item of the array returned by the query generator.
- return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
+ // Check for embeddable / component element
+ if(type instanceof ComponentType) {
+ final Component component = (Component) value;
+ final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper(new MultiPropertyMapper(), component.getComponentClassName());
+
+ // Embeddable properties must be added as non-composite-id properties
+ // since embeddable properties can be nullable and can't be contained within
+ // the primary key
+ final Element parent = xmlMapping.getParent();
+ final ComponentAuditingData auditData = new ComponentAuditingData();
+ final ReflectionManager reflectionManager = mainGenerator.getCfg().getReflectionManager();
+
+ // Read metadata from annotations
+ new AuditedPropertiesReader(ModificationStore.FULL, new AuditedPropertiesReader.ComponentPropertiesSource(reflectionManager, component), auditData,
+ mainGenerator.getGlobalCfg(), reflectionManager, "").read();
+
+ for(final String auditedPropertyName : auditData.getPropertyNames()) {
+ final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData(auditedPropertyName);
+ mainGenerator.addValue(parent, component.getProperty(auditedPropertyName).getValue(), componentMapper, prefix, xmlMappingData, nestedAuditingData, true, true);
+ }
+
+ // Add an additional column holding a number to make each entry unique within the set,
+ // since embeddable properties can be null
+ if(propertyValue.getCollectionType() instanceof SetType) {
+ final String auditedEmbeddableSetOrdinalPropertyName = mainGenerator.getVerEntCfg().getEmbeddableSetOrdinalPropertyName();
+ final String auditedEmbeddableSetOrdinalPropertyType = mainGenerator.getVerEntCfg().getEmbeddableSetOrdinalPropertyType();
+
+ final SimpleValue simpleValue = new SimpleValue(component.getMappings(), component.getTable());
+ simpleValue.setTypeName(auditedEmbeddableSetOrdinalPropertyType);
+
+ final Element idProperty = MetadataTools.addProperty(xmlMapping, auditedEmbeddableSetOrdinalPropertyName,
+ auditedEmbeddableSetOrdinalPropertyType, true, true);
+ MetadataTools.addColumn(idProperty, auditedEmbeddableSetOrdinalPropertyName, null, 0, 0, null, null, null, false);
+ }
+
+ return new MiddleComponentData(componentMapper, 0);
} else {
- mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
- // Impossible to get here.
- throw new AssertionError();
+ // Last but one parameter: collection components are always insertable
+ boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
+ new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false),
+ value, null, true, true);
+
+ if (mapped) {
+ // Simple values are always stored in the first item of the array returned by the query generator.
+ return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
+ } else {
+ mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
+ // Impossible to get here.
+ throw new AssertionError();
+ }
}
}
}
private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
Type type = propertyValue.getType();
+ final boolean embeddableElementType = isEmbeddableElementType();
+
if (type instanceof SortedSetType) {
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
- new SortedSetCollectionMapper(commonCollectionMapperData,
- TreeSet.class, SortedSetProxy.class, elementComponentData, propertyValue.getComparator()));
+ new SortedSetCollectionMapper(commonCollectionMapperData,
+ TreeSet.class, SortedSetProxy.class, elementComponentData, embeddableElementType, embeddableElementType, propertyValue.getComparator()));
} else if (type instanceof SetType) {
- currentMapper.addComposite(propertyAuditingData.getPropertyData(),
+ currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<Set>(commonCollectionMapperData,
- HashSet.class, SetProxy.class, elementComponentData));
+ HashSet.class, SetProxy.class, elementComponentData, embeddableElementType, embeddableElementType));
} else if (type instanceof SortedMapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new SortedMapCollectionMapper(commonCollectionMapperData,
- TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData, propertyValue.getComparator()));
+ TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData, propertyValue.getComparator(), embeddableElementType));
} else if (type instanceof MapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new MapCollectionMapper<Map>(commonCollectionMapperData,
- HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
+ HashMap.class, MapProxy.class, elementComponentData, indexComponentData, embeddableElementType));
} else if (type instanceof BagType) {
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new BasicCollectionMapper<List>(commonCollectionMapperData,
- ArrayList.class, ListProxy.class, elementComponentData));
+ ArrayList.class, ListProxy.class, elementComponentData, embeddableElementType, embeddableElementType));
} else if (type instanceof ListType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyAuditingData.getPropertyData(),
new ListCollectionMapper(commonCollectionMapperData,
- elementComponentData, indexComponentData));
+ elementComponentData, indexComponentData, embeddableElementType));
} else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
}
@@ -543,7 +591,7 @@ private Element createMiddleEntityXml(String auditMiddleTableName, String auditM
mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
// Adding the revision type property to the entity xml.
- mainGenerator.addRevisionType(middleEntityXml);
+ mainGenerator.addRevisionType((isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml), middleEntityXml);
// All other properties should also be part of the primary key of the middle entity.
return middleEntityXmlId;
@@ -644,4 +692,11 @@ private String searchMappedBy(PersistentClass referencedClass, Table collectionT
return null;
}
+
+ /**
+ * Checks if the collection element type is a {@link ComponentType}.
+ */
+ private boolean isEmbeddableElementType() {
+ return (propertyValue.getElement().getType() instanceof ComponentType);
+ }
}
View
13 ...vers/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
@@ -49,15 +49,18 @@
private final MiddleIdData referencingIdData;
private final String auditMiddleEntityName;
private final List<MiddleIdData> idDatas;
+ private final boolean revisionTypeInId;
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy,
- MiddleIdData referencingIdData, String auditMiddleEntityName) {
+ MiddleIdData referencingIdData, String auditMiddleEntityName,
+ final boolean revisionTypeInId) {
this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
this.auditStrategy = auditStrategy;
this.referencingIdData = referencingIdData;
this.auditMiddleEntityName = auditMiddleEntityName;
+ this.revisionTypeInId = revisionTypeInId;
idDatas = new ArrayList<MiddleIdData>();
}
@@ -69,14 +72,14 @@ void addRelation(MiddleIdData idData) {
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
if (idDatas.size() == 0) {
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
- componentDatas);
+ revisionTypeInId, componentDatas);
} else if (idDatas.size() == 1) {
if (idDatas.get(0).isAudited()) {
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
- idDatas.get(0), componentDatas);
+ idDatas.get(0), revisionTypeInId, componentDatas);
} else {
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
- idDatas.get(0), componentDatas);
+ idDatas.get(0), revisionTypeInId, componentDatas);
}
} else if (idDatas.size() == 2) {
// All entities must be audited.
@@ -85,7 +88,7 @@ RelationQueryGenerator build(MiddleComponentData... componentDatas) {
}
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
- idDatas.get(0), idDatas.get(1), componentDatas);
+ idDatas.get(0), idDatas.get(1), revisionTypeInId, componentDatas);
} else {
throw new IllegalStateException("Illegal number of related entities.");
}
View
4 ...main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesHolder.java
@@ -31,4 +31,8 @@
*/
boolean contains(String propertyName);
+ /**
+ * @return an {@link Iterable} for the property names.
+ */
+ Iterable<String> getPropertyNames();
}
View
8 ...main/java/org/hibernate/envers/configuration/metadata/reader/AuditedPropertiesReader.java
@@ -224,7 +224,7 @@ private void addFromPropertiesGroup(String embeddedName, XProperty property, Str
// Marking component properties as placed directly in class (not inside another component).
componentData.setBeanName(null);
- PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource((Component) propertyValue);
+ PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(reflectionManager, (Component) propertyValue);
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
@@ -242,7 +242,7 @@ private void addFromComponentProperty(XProperty property,
boolean isAudited = fillPropertyData(property, componentData, accessType,
allClassAudited);
- PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
+ PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(reflectionManager,
(Component) propertyValue);
ComponentAuditedPropertiesReader audPropReader = new ComponentAuditedPropertiesReader(
@@ -415,11 +415,11 @@ private boolean processPropertyAuditingOverrides(XProperty property, PropertyAud
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};
- private class ComponentPropertiesSource implements PersistentPropertiesSource {
+ public static class ComponentPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass;
private final Component component;
- private ComponentPropertiesSource(Component component) {
+ public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) {
try {
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
} catch (ClassNotFoundException e) {
View
4 ...c/main/java/org/hibernate/envers/configuration/metadata/reader/ComponentAuditingData.java
@@ -51,6 +51,10 @@ public PropertyAuditingData getPropertyAuditingData(String propertyName) {
return properties.get(propertyName);
}
+ public Iterable<String> getPropertyNames() {
+ return properties.keySet();
+ }
+
public boolean contains(String propertyName) {
return properties.containsKey(propertyName);
}
View
8 hibernate-envers/src/main/java/org/hibernate/envers/entities/EntityInstantiator.java
@@ -45,6 +45,14 @@ public EntityInstantiator(AuditConfiguration verCfg, AuditReaderImplementor vers
this.verCfg = verCfg;
this.versionsReader = versionsReader;
}
+
+ public AuditConfiguration getAuditConfiguration() {
+ return verCfg;
+ }
+
+ public AuditReaderImplementor getAuditReaderImplementor() {
+ return versionsReader;
+ }
/**
* Creates an entity instance based on an entry from the versions table.
View
7 ...te-envers/src/main/java/org/hibernate/envers/entities/mapper/ComponentPropertyMapper.java
@@ -105,11 +105,14 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
}
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
- return delegate.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
+ return delegate.mapCollectionChanges(session, referencingPropertyName, newColl, oldColl, id);
}
+ public Map<PropertyData, PropertyMapper> getProperties() {
+ return delegate.getProperties();
+ }
}
View
3 ...ate-envers/src/main/java/org/hibernate/envers/entities/mapper/CompositeMapperBuilder.java
@@ -22,6 +22,8 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.entities.mapper;
+import java.util.Map;
+
import org.hibernate.envers.entities.PropertyData;
/**
@@ -30,4 +32,5 @@
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
public CompositeMapperBuilder addComponent(PropertyData propertyData, String componentClassName);
public void addComposite(PropertyData propertyData, PropertyMapper propertyMapper);
+ public Map<PropertyData, PropertyMapper> getProperties();
}
View
2 ...ate-envers/src/main/java/org/hibernate/envers/entities/mapper/ExtendedPropertyMapper.java
@@ -31,4 +31,6 @@
*/
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
public boolean map(SessionImplementor session, Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
+
+ public PropertyMapper getMapper(String propertyName);
}
View
14 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/MultiPropertyMapper.java
@@ -30,6 +30,7 @@
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.PropertyData;
+import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.MappingTools;
import org.hibernate.envers.tools.Tools;
@@ -80,7 +81,7 @@ public boolean map(SessionImplementor session, Map<String, Object> data, String[
String propertyName = propertyNames[i];
if (propertyDatas.containsKey(propertyName)) {
- ret |= properties.get(propertyDatas.get(propertyName)).mapToMapFromEntity(session, data,
+ ret |= getMapper(propertyName).mapToMapFromEntity(session, data,
getAtIndexOrNull(newState, i),
getAtIndexOrNull(oldState, i));
}
@@ -116,7 +117,8 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
}
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
@@ -141,9 +143,9 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
delegatePropertyName = referencingPropertyName;
}
- PropertyMapper mapper = properties.get(propertyDatas.get(referencingPropertyName));
+ PropertyMapper mapper = getMapper(referencingPropertyName);
if (mapper != null) {
- return mapper.mapCollectionChanges(delegatePropertyName, newColl, oldColl, id);
+ return mapper.mapCollectionChanges(session, delegatePropertyName, newColl, oldColl, id);
} else {
return null;
}
@@ -152,4 +154,8 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
public Map<PropertyData, PropertyMapper> getProperties() {
return properties;
}
+
+ public PropertyMapper getMapper(String propertyName) {
+ return properties.get(propertyDatas.get(propertyName));
+ }
}
View
3 hibernate-envers/src/main/java/org/hibernate/envers/entities/mapper/PropertyMapper.java
@@ -59,13 +59,14 @@ void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object
/**
* Maps collection changes
+ * @param session The current session.
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
* @param newColl New collection, after updates.
* @param oldColl Old collection, before updates.
* @param id Id of the object owning the collection.
* @return List of changes that need to be performed on the persistent store.
*/
- List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session, String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id);
}
View
5 ...rnate-envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java
@@ -97,11 +97,12 @@ private boolean isPrimitive(Setter setter, PropertyData propertyData, Class<?> c
}
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
return null;
}
-}
+}
View
20 ...ate-envers/src/main/java/org/hibernate/envers/entities/mapper/SubclassPropertyMapper.java
@@ -23,6 +23,7 @@
*/
package org.hibernate.envers.entities.mapper;
import java.io.Serializable;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -65,15 +66,16 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
List<PersistentCollectionChangeData> parentCollectionChanges = parentMapper.mapCollectionChanges(
- referencingPropertyName, newColl, oldColl, id);
+ session, referencingPropertyName, newColl, oldColl, id);
List<PersistentCollectionChangeData> mainCollectionChanges = main.mapCollectionChanges(
- referencingPropertyName, newColl, oldColl, id);
+ session, referencingPropertyName, newColl, oldColl, id);
if (parentCollectionChanges == null) {
return mainCollectionChanges;
@@ -96,4 +98,16 @@ public void addComposite(PropertyData propertyData, PropertyMapper propertyMappe
public void add(PropertyData propertyData) {
main.add(propertyData);
}
+
+ public PropertyMapper getMapper(String propertyName) {
+ PropertyMapper mapper = main.getMapper(propertyName);
+ return (mapper != null ? mapper : parentMapper.getMapper(propertyName));
+ }
+
+ public Map<PropertyData, PropertyMapper> getProperties() {
+ final Map<PropertyData, PropertyMapper> joinedProperties = new HashMap<PropertyData, PropertyMapper>();
+ joinedProperties.putAll(parentMapper.getProperties());
+ joinedProperties.putAll(main.getProperties());
+ return joinedProperties;
+ }
}
View
57 ...src/main/java/org/hibernate/envers/entities/mapper/relation/AbstractCollectionMapper.java
@@ -38,7 +38,6 @@
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
-import org.hibernate.envers.entities.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.reader.AuditReaderImplementor;
@@ -48,14 +47,18 @@
/**
* @author Adam Warski (adam at warski dot org)
*/
-public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
+public abstract class AbstractCollectionMapper<T> implements CollectionPropertyMapper {
protected final CommonCollectionMapperData commonCollectionMapperData;
protected final Class<? extends T> collectionClass;
private final Constructor<? extends T> proxyConstructor;
+
+ protected final boolean ordinalInId;
+ protected final boolean revisionTypeInId;
protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
- Class<? extends T> collectionClass, Class<? extends T> proxyClass) {
+ Class<? extends T> collectionClass, Class<? extends T> proxyClass,
+ boolean ordinalInId, boolean revisionTypeInId) {
this.commonCollectionMapperData = commonCollectionMapperData;
this.collectionClass = collectionClass;
@@ -64,23 +67,54 @@ protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMa
} catch (NoSuchMethodException e) {
throw new AuditException(e);
}
+
+ this.ordinalInId = ordinalInId;
+ this.revisionTypeInId = revisionTypeInId;
}
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
/**
* Maps the changed collection element to the given map.
+ * @param session The SessionImplementor reference.
+ * @param idData Map to which composite-id data should be added.
* @param data Where to map the data.
* @param changed The changed collection element to map.
*/
- protected abstract void mapToMapFromObject(Map<String, Object> data, Object changed);
+ protected abstract void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData,
+ Map<String, Object> data, Object changed);
- private void addCollectionChanges(List<PersistentCollectionChangeData> collectionChanges, Set<Object> changed,
+ /**
+ * Creates a new empty Map.
+ *
+ * <p>
+ * The ordinal parameter represents the iteration ordinal of the current element,
+ * used to add a synthetic id when dealing with embeddables since embeddable fields
+ * can't be contained within the primary key since they might be nullable.
+ * </p>
+ *
+ * @param ordinal The element iteration ordinal.
+ *
+ * @return A Map for holding the ID information.
+ */
+ protected Map<String, Object> createIdMap(int ordinal) {
+ final HashMap<String, Object> idMap = new HashMap<String, Object>();
+
+ if(ordinalInId) {
+ idMap.put(this.commonCollectionMapperData.getVerEntCfg().getEmbeddableSetOrdinalPropertyName(), Integer.valueOf(ordinal));
+ }
+
+ return idMap;
+ }
+
+ private void addCollectionChanges(SessionImplementor session, List<PersistentCollectionChangeData> collectionChanges, Set<Object> changed,
RevisionType revisionType, Serializable id) {
+ int ordinal = 0;
+
for (Object changedObj : changed) {
Map<String, Object> entityData = new HashMap<String, Object>();
- Map<String, Object> originalId = new HashMap<String, Object>();
+ Map<String, Object> originalId = createIdMap(ordinal++);
entityData.put(commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId);
collectionChanges.add(new PersistentCollectionChangeData(
@@ -89,14 +123,15 @@ private void addCollectionChanges(List<PersistentCollectionChangeData> collectio
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id);
// Mapping collection element and index (if present).
- mapToMapFromObject(originalId, changedObj);
+ mapToMapFromObject(session, originalId, entityData, changedObj);
- entityData.put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
+ (revisionTypeInId ? originalId : entityData).put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
}
}
@SuppressWarnings({"unchecked"})
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
if (!commonCollectionMapperData.getCollectionReferencingPropertyData().getName()
@@ -116,14 +151,14 @@ private void addCollectionChanges(List<PersistentCollectionChangeData> collectio
// removeAll in AbstractSet has an implementation that is hashcode-change sensitive (as opposed to addAll).
if (oldColl != null) { added.removeAll(new HashSet(oldCollection)); }
- addCollectionChanges(collectionChanges, added, RevisionType.ADD, id);
+ addCollectionChanges(session, collectionChanges, added, RevisionType.ADD, id);
Set<Object> deleted = new HashSet<Object>();
if (oldColl != null) { deleted.addAll(oldCollection); }
// The same as above - re-hashing new collection.
if (newColl != null) { deleted.removeAll(new HashSet(newCollection)); }
- addCollectionChanges(collectionChanges, deleted, RevisionType.DEL, id);
+ addCollectionChanges(session, collectionChanges, deleted, RevisionType.DEL, id);
return collectionChanges;
}
View
14 ...rs/src/main/java/org/hibernate/envers/entities/mapper/relation/BasicCollectionMapper.java
@@ -28,6 +28,7 @@
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.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.BasicCollectionInitializor;
@@ -42,8 +43,9 @@
public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
- MiddleComponentData elementComponentData) {
- super(commonCollectionMapperData, collectionClass, proxyClass);
+ MiddleComponentData elementComponentData,
+ boolean ordinalInId, boolean revisionTypeInId) {
+ super(commonCollectionMapperData, collectionClass, proxyClass, ordinalInId, revisionTypeInId);
this.elementComponentData = elementComponentData;
}
@@ -67,7 +69,11 @@ protected Collection getOldCollectionContent(Serializable oldCollection) {
}
}
- protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
- elementComponentData.getComponentMapper().mapToMapFromObject(data, changed);
+ protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
+ elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, changed);
+ }
+
+ public boolean needsDataComparision() {
+ return elementComponentData.getComponentMapper().needsDataComparision();
}
}
View
27 ...src/main/java/org/hibernate/envers/entities/mapper/relation/CollectionPropertyMapper.java
@@ -0,0 +1,27 @@
+package org.hibernate.envers.entities.mapper.relation;
+
+import javax.persistence.ElementCollection;
+import javax.persistence.Embeddable;
+
+import org.hibernate.envers.entities.mapper.PropertyMapper;
+import org.hibernate.envers.strategy.ValidityAuditStrategy;
+
+/**
+ * An extension to the {@link PropertyMapper} interface
+ * used for controlling the revision query creation
+ * used by the {@link ValidityAuditStrategy}.
+ *
+ * @author Kristoffer Lundberg
+ *
+ * @see ValidityAuditStrategy
+ */
+public interface CollectionPropertyMapper extends PropertyMapper {
+ /**
+ * Checks if the query needs to compare data
+ * outside of the primary key.
+ *
+ * This is only the case for {@link ElementCollection}s
+ * of {@link Embeddable}s.
+ */
+ boolean needsDataComparision();
+}
View
16 ...ers/src/main/java/org/hibernate/envers/entities/mapper/relation/ListCollectionMapper.java
@@ -28,6 +28,7 @@
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.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
@@ -45,8 +46,9 @@
private final MiddleComponentData indexComponentData;
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
- MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
- super(commonCollectionMapperData, List.class, ListProxy.class);
+ MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
+ boolean revisionTypeInId) {
+ super(commonCollectionMapperData, List.class, ListProxy.class, false, revisionTypeInId);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
@@ -76,9 +78,13 @@ protected Collection getOldCollectionContent(Serializable oldCollection) {
}
@SuppressWarnings({"unchecked"})
- protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
+ protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed;
- elementComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getSecond());
- indexComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getFirst());
+ elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getSecond());
+ indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, indexValuePair.getFirst());
+ }
+
+ public boolean needsDataComparision() {
+ return elementComponentData.getComponentMapper().needsDataComparision();
}
}
View
16 ...vers/src/main/java/org/hibernate/envers/entities/mapper/relation/MapCollectionMapper.java
@@ -28,6 +28,7 @@
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.mapper.PropertyMapper;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
@@ -43,8 +44,9 @@
public MapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
- MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
- super(commonCollectionMapperData, collectionClass, proxyClass);
+ MiddleComponentData elementComponentData, MiddleComponentData indexComponentData,
+ boolean revisionTypeInId) {
+ super(commonCollectionMapperData, collectionClass, proxyClass, false, revisionTypeInId);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
@@ -71,8 +73,12 @@ protected Collection getOldCollectionContent(Serializable oldCollection) {
}
}
- protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
- elementComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getValue());
- indexComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getKey());
+ protected void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object changed) {
+ elementComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getValue());
+ indexComponentData.getComponentMapper().mapToMapFromObject(session, idData, data, ((Map.Entry) changed).getKey());
+ }
+
+ public boolean needsDataComparision() {
+ return elementComponentData.getComponentMapper().needsDataComparision();
}
}
View
4 .../src/main/java/org/hibernate/envers/entities/mapper/relation/OneToOneNotOwningMapper.java
@@ -38,6 +38,7 @@
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.reader.AuditReaderImplementor;
+import org.hibernate.envers.tools.query.QueryBuilder;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.property.Setter;
@@ -90,7 +91,8 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
setter.set(obj, value, null);
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
View
5 ...rc/main/java/org/hibernate/envers/entities/mapper/relation/SortedMapCollectionMapper.java
@@ -39,8 +39,9 @@
public SortedMapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends SortedMap> collectionClass, Class<? extends SortedMap> proxyClass,
- MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator) {
- super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData);
+ MiddleComponentData elementComponentData, MiddleComponentData indexComponentData, Comparator comparator,
+ boolean revisionTypeInId) {
+ super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, indexComponentData, revisionTypeInId);
this.comparator = comparator;
}
View
5 ...rc/main/java/org/hibernate/envers/entities/mapper/relation/SortedSetCollectionMapper.java
@@ -39,8 +39,9 @@
public SortedSetCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends SortedSet> collectionClass, Class<? extends SortedSet> proxyClass,
- MiddleComponentData elementComponentData, Comparator comparator) {
- super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData);
+ MiddleComponentData elementComponentData, boolean ordinalInId, boolean revisionTypeInId,
+ Comparator comparator) {
+ super(commonCollectionMapperData, collectionClass, proxyClass, elementComponentData, ordinalInId, revisionTypeInId);
this.comparator = comparator;
}
View
3 ...ate-envers/src/main/java/org/hibernate/envers/entities/mapper/relation/ToOneIdMapper.java
@@ -107,7 +107,8 @@ public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data,
setter.set(obj, value, null);
}
- public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
+ public List<PersistentCollectionChangeData> mapCollectionChanges(SessionImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
View
21 ...n/java/org/hibernate/envers/entities/mapper/relation/component/MiddleComponentMapper.java
@@ -24,6 +24,10 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import javax.persistence.ElementCollection;
+import javax.persistence.Embeddable;
+
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters;
@@ -45,18 +49,31 @@ Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String,
/**
* Maps from an object to the object's map representation (for an entity - only its id).
+ * @param session The current session.
+ * @param idData Map to which composite-id data should be added.
* @param data Map to which data should be added.
* @param obj Object to map from.
*/
- void mapToMapFromObject(Map<String, Object> data, Object obj);
+ void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj);
/**
* Adds query statements, which contains restrictions, which express the property that part of the middle
* entity with alias prefix1, is equal to part of the middle entity with alias prefix2 (the entity is the same).
* The part is the component's representation in the middle entity.
* @param parameters Parameters, to which to add the statements.
+ * @param idPrefix1 First alias of the entity + prefix + id to add to the properties.
* @param prefix1 First alias of the entity + prefix to add to the properties.
+ * @param idPrefix2 Second alias of the entity + prefix + id to add to the properties.
* @param prefix2 Second alias of the entity + prefix to add to the properties.
*/
- void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2);
+ void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2);
+
+ /**
+ * Checks if the query needs to compare data
+ * outside of the primary key.
+ *
+ * This is only the case for {@link ElementCollection}s
+ * of {@link Embeddable}s.
+ */
+ boolean needsDataComparision();
}
View
9 ...a/org/hibernate/envers/entities/mapper/relation/component/MiddleDummyComponentMapper.java
@@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters;
@@ -36,9 +37,13 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return null;
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
+ }
+
+ public boolean needsDataComparision() {
+ return false;
}
}
View
113 .../hibernate/envers/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java
@@ -0,0 +1,113 @@
+/*
+ * 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.entities.mapper.relation.component;
+
+import java.util.Map;
+
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.envers.entities.EntityInstantiator;
+import org.hibernate.envers.entities.PropertyData;
+import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
+import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
+import org.hibernate.envers.entities.mapper.PropertyMapper;
+import org.hibernate.envers.exception.AuditException;
+import org.hibernate.envers.tools.query.Parameters;
+import org.hibernate.internal.util.ReflectHelper;
+
+/**
+ * A {@link MiddleComponentMapper} implementation for embeddables / components,
+ * assembling and disassembling the component via a {@link MultiPropertyMapper}.
+ *
+ * <p>
+ * All methods except {@link #addMiddleEqualToQuery(Parameters, String, String, String, String)} delegate to a {@link MultiPropertyMapper}.
+ * </p>
+ *
+ * <p>
+ * {@link #addMiddleEqualToQuery(Parameters, String, String, String, String)} adds all properties
+ * to the where clause.
+ * </p>
+ *
+ * @author Kristoffer Lundberg (kristoffer at cambio dot se)
+ */
+public final class MiddleEmbeddableComponentMapper implements MiddleComponentMapper, CompositeMapperBuilder {
+ private final MultiPropertyMapper delegate;
+ private final String componentClassName;
+
+ public MiddleEmbeddableComponentMapper(final MultiPropertyMapper delegate, final String componentClassName) {
+ this.delegate = delegate;
+ this.componentClassName = componentClassName;
+ }
+
+ public void add(PropertyData propertyData) {
+ delegate.add(propertyData);
+ }
+
+ public CompositeMapperBuilder addComponent(final PropertyData propertyData, final String componentClassName) {
+ return delegate.addComponent(propertyData, componentClassName);
+ }
+
+ public void addComposite(final PropertyData propertyData, final PropertyMapper propertyMapper) {
+ delegate.addComposite(propertyData, propertyMapper);
+ }
+
+ public Object mapToObjectFromFullMap(final EntityInstantiator entityInstantiator,
+ final Map<String, Object> data, final Object dataObject, final Number revision) {
+ try {
+ final Object componentInstance = (dataObject != null ? dataObject : ReflectHelper.getDefaultConstructor(Thread.currentThread().getContextClassLoader().loadClass(componentClassName)).newInstance());
+ this.delegate.mapToEntityFromMap(entityInstantiator.getAuditConfiguration(), componentInstance, data, null, entityInstantiator.getAuditReaderImplementor(), revision);
+ return componentInstance;
+ } catch(Exception e) {
+ throw new AuditException(e);
+ }
+ }
+
+ public void mapToMapFromObject(final SessionImplementor session, final Map<String, Object> idData, final Map<String, Object> data, final Object obj) {
+ delegate.mapToMapFromEntity(session, data, obj, obj);
+ }
+
+ public void addMiddleEqualToQuery(final Parameters parameters, final String idPrefix1, final String prefix1, final String idPrefix2, final String prefix2) {
+ addMiddleEqualToQuery(delegate, parameters, idPrefix1, prefix1, idPrefix2, prefix2);
+ }
+
+ protected void addMiddleEqualToQuery(final CompositeMapperBuilder compositeMapper, final Parameters parameters, final String idPrefix1, final String prefix1, final String idPrefix2, final String prefix2) {
+ for(final Map.Entry<PropertyData, PropertyMapper> entry : compositeMapper.getProperties().entrySet()) {
+ final String propertyName = entry.getKey().getName();
+ final PropertyMapper nestedMapper = entry.getValue();
+
+ if(nestedMapper instanceof CompositeMapperBuilder) {
+ addMiddleEqualToQuery((CompositeMapperBuilder) nestedMapper, parameters, idPrefix1, prefix1, idPrefix2, prefix2);
+ } else {
+ parameters.addWhere(prefix1 + '.' + propertyName, false, "=", prefix2 + '.' + propertyName, false);
+ }
+ }
+ }
+
+ public boolean needsDataComparision() {
+ return true;
+ }
+
+ public Map<PropertyData, PropertyMapper> getProperties() {
+ return delegate.getProperties();
+ }
+}
View
9 ...rg/hibernate/envers/entities/mapper/relation/component/MiddleMapKeyIdComponentMapper.java
@@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.entities.mapper.id.IdMapper;
@@ -49,11 +50,15 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return relatedIdMapper.mapToIdFromMap((Map) data.get(verEntCfg.getOriginalIdPropName()));
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
// Doing nothing.
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
// Doing nothing.
}
+
+ public boolean needsDataComparision() {
+ return false;
+ }
}
View
9 ...ernate/envers/entities/mapper/relation/component/MiddleMapKeyPropertyComponentMapper.java
@@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters;
import org.hibernate.envers.tools.reflection.ReflectionTools;
@@ -49,11 +50,15 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return ReflectionTools.getGetter(dataObject.getClass(), propertyName, accessType).get(dataObject);
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
// Doing nothing.
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
// Doing nothing.
}
+
+ public boolean needsDataComparision() {
+ return false;
+ }
}
View
13 ...org/hibernate/envers/entities/mapper/relation/component/MiddleRelatedComponentMapper.java
@@ -24,6 +24,7 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
import org.hibernate.envers.tools.query.Parameters;
@@ -43,11 +44,15 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return entityInstantiator.createInstanceFromVersionsEntity(relatedIdData.getEntityName(), data, revision);
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
- relatedIdData.getPrefixedMapper().mapToMapFromEntity(data, obj);
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
+ relatedIdData.getPrefixedMapper().mapToMapFromEntity(idData, obj);
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
- relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, prefix1, prefix2);
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
+ relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, idPrefix1, idPrefix2);
+ }
+
+ public boolean needsDataComparision() {
+ return false;
}
}
View
14 .../org/hibernate/envers/entities/mapper/relation/component/MiddleSimpleComponentMapper.java
@@ -24,9 +24,11 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters;
+import org.hibernate.envers.tools.query.QueryBuilder;
/**
* @author Adam Warski (adam at warski dot org)
@@ -46,11 +48,15 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return ((Map<String, Object>) data.get(verEntCfg.getOriginalIdPropName())).get(propertyName);
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
- data.put(propertyName, obj);
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
+ idData.put(propertyName, obj);
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
- parameters.addWhere(prefix1 + "." + propertyName, false, "=", prefix2 + "." + propertyName, false);
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
+ parameters.addWhere(idPrefix1 + "." + propertyName, false, "=", idPrefix2 + "." + propertyName, false);
+ }
+
+ public boolean needsDataComparision() {
+ return false;
}
}
View
13 ...rg/hibernate/envers/entities/mapper/relation/component/MiddleStraightComponentMapper.java
@@ -24,12 +24,13 @@
package org.hibernate.envers.entities.mapper.relation.component;
import java.util.Map;
+import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.entities.EntityInstantiator;
import org.hibernate.envers.tools.query.Parameters;
/**
* A mapper for reading and writing a property straight to/from maps. This mapper cannot be used with middle tables,
- * but only with "fake" bidirectional indexed relations.
+ * but only with "fake" bidirectional indexed relations.
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleStraightComponentMapper implements MiddleComponentMapper {
@@ -45,11 +46,15 @@ public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<
return data.get(propertyName);
}
- public void mapToMapFromObject(Map<String, Object> data, Object obj) {
- data.put(propertyName, obj);
+ public void mapToMapFromObject(SessionImplementor session, Map<String, Object> idData, Map<String, Object> data, Object obj) {
+ idData.put(propertyName, obj);
}
- public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
+ public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1, String idPrefix2, String prefix2) {
throw new UnsupportedOperationException("Cannot use this mapper with a middle table!");
}
+
+ public boolean needsDataComparision() {
+ return false;
+ }
}
View
6 ...ain/java/org/hibernate/envers/entities/mapper/relation/query/OneEntityQueryGenerator.java
@@ -47,6 +47,7 @@ public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
AuditStrategy auditStrategy,
String versionsMiddleEntityName,
MiddleIdData referencingIdData,
+ boolean revisionTypeInId,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
@@ -86,10 +87,11 @@ public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
// --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
- eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
+ eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, "ee", componentDatas);
// ee.revision_type != DEL
- rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
+ final String revisionTypePropertyName = (revisionTypeInId ? verEntCfg.getOriginalIdPropName() + '.' + verEntCfg.getRevisionTypePropName() : verEntCfg.getRevisionTypePropName());
+ rootParameters.addWhereWithNamedParam(revisionTypePropertyName, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
View
10 ...n/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
@@ -51,6 +51,7 @@ public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
MiddleIdData referencingIdData,
MiddleIdData referencedIdData,
MiddleIdData indexIdData,
+ boolean revisionTypeInId,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
@@ -148,14 +149,15 @@ public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
// --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
- eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
+ eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, "ee", componentDatas);
// ee.revision_type != DEL
- rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
+ final String revisionTypePropName = (revisionTypeInId ? verEntCfg.getOriginalIdPropName() + '.' + verEntCfg.getRevisionTypePropName() : verEntCfg.getRevisionTypePropName());
+ rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", "delrevisiontype");
// e.revision_type != DEL
- rootParameters.addWhereWithNamedParam("e." + verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
+ rootParameters.addWhereWithNamedParam("e." + revisionTypePropName, false, "!=", "delrevisiontype");
// f.revision_type != DEL
- rootParameters.addWhereWithNamedParam("f." + verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
+ rootParameters.addWhereWithNamedParam("f." + revisionTypePropName, false, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
View
6 ...rg/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
@@ -47,6 +47,7 @@ public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, A
String versionsMiddleEntityName,
MiddleIdData referencingIdData,
MiddleIdData referencedIdData,
+ boolean revisionTypeInId,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
@@ -93,10 +94,11 @@ public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, A
// --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
- eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
+ eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, "ee", componentDatas);
// ee.revision_type != DEL
- rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
+ final String revisionTypePropName = (revisionTypeInId ? verEntCfg.getOriginalIdPropName() + '.' + verEntCfg.getRevisionTypePropName() : verEntCfg.getRevisionTypePropName());
+ rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
View
8 ...ain/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
@@ -50,6 +50,7 @@ public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
String versionsMiddleEntityName,
MiddleIdData referencingIdData,
MiddleIdData referencedIdData,
+ boolean revisionTypeInId,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
@@ -111,12 +112,13 @@ public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
// --> based on auditStrategy (see above)
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
- eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
+ eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, "ee", componentDatas);
// ee.revision_type != DEL
- rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
+ final String revisionTypePropName = (revisionTypeInId ? verEntCfg.getOriginalIdPropName() + '.' + verEntCfg.getRevisionTypePropName() : verEntCfg.getRevisionTypePropName());
+ rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", "delrevisiontype");
// e.revision_type != DEL
- rootParameters.addWhereWithNamedParam("e." + verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
+ rootParameters.addWhereWithNamedParam("e." + revisionTypePropName, false, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
View
2 ...te-envers/src/main/java/org/hibernate/envers/event/BaseEnversCollectionEventListener.java
@@ -151,7 +151,7 @@ private void generateFakeBidirecationalRelationWorkUnits(
.getEntCfg()
.get( collectionEntityName )
.getPropertyMapper()
- .mapCollectionChanges( referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() );
+ .mapCollectionChanges(event.getSession(), referencingPropertyName, newColl, oldColl, event.getAffectedOwnerIdOrNull() );
// Getting the id mapper for the related entity, as the work units generated will corrspond to the related
// entities.
View
30 hibernate-envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
@@ -2,6 +2,7 @@
import java.io.Serializable;
import org.hibernate.Session;
+import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
@@ -11,14 +12,14 @@
/**
* Behaviours of different audit strategy for populating audit data.
- *
+ *
* @author Stephanie Pau
* @author Adam Warski (adam at warski dot org)
*/
public interface AuditStrategy {
/**
* Perform the persistence of audited data for regular entities.
- *
+ *
* @param session Session, which can be used to persist the data.
* @param entityName Name of the entity, in which the audited change happens
* @param auditCfg Audit configuration
@@ -33,26 +34,28 @@ void perform(Session session, String entityName, AuditConfiguration auditCfg, Se
* Perform the persistence of audited data for collection ("middle") entities.
*
* @param session Session, which can be used to persist the data.
+ * @param entityName Name of the entity, in which the audited change happens
+ * @param propertyName The name of the property holding the {@link PersistentCollection}.
* @param auditCfg Audit configuration
* @param persistentCollectionChangeData Collection change data to be persisted.
* @param revision Current revision data
*/
- void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
-
+
/**
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation.
* This WHERE clause depends on the AuditStrategy, as follows:
* <ul>
- * <li>For {@link DefaultAuditStrategy} a subquery is created:
+ * <li>For {@link DefaultAuditStrategy} a subquery is created:
* <p><code>e.revision = (SELECT max(...) ...)</code></p>
* </li>
- * <li>for {@link ValidityAuditStrategy} the revision-end column is used:
+ * <li>for {@link ValidityAuditStrategy} the revision-end column is used:
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
* </li>
* </ul>
- *
+ *
* @param globalCfg the {@link GlobalConfiguration}
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
* @param revisionProperty property of the revision column
@@ -89,11 +92,12 @@ void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidityAuditStrategy})
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
- * @param componentDatas information about the middle-entity relation
- */
- void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
- String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
- String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
- String originalIdPropertyName, MiddleComponentData... componentDatas);
+ * @param alias1 an alias used for subqueries.
+ * @param componentDatas information about the middle-entity relation
+ */
+ void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
+ String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
+ String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
+ String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas);
}
View
6 hibernate-envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
@@ -30,7 +30,7 @@ public void perform(Session session, String entityName, AuditConfiguration audit
sessionCacheCleaner.scheduleAuditDataRemoval(session, data);
}
- public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData());
@@ -62,7 +62,7 @@ public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryB
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
String eeOriginalIdPropertyPath, String revisionPropertyPath,
- String originalIdPropertyName, MiddleComponentData... componentDatas) {
+ String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
Parameters rootParameters = rootQueryBuilder.getRootParameters();
// SELECT max(ee2.revision) FROM middleEntity ee2
@@ -76,7 +76,7 @@ public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder,
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
for (MiddleComponentData componentData : componentDatas) {
- componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
+ componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, alias1, ee2OriginalIdPropertyPath, "ee2");
}
// add subquery to rootParameters
View
30 hibernate-envers/src/main/java/org/hibernate/envers/strategy/ValidityAuditStrategy.java
@@ -12,6 +12,7 @@
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
import org.hibernate.envers.entities.mapper.id.IdMapper;
+import org.hibernate.envers.entities.mapper.relation.CollectionPropertyMapper;
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
import org.hibernate.envers.synchronization.SessionCacheCleaner;
@@ -84,21 +85,39 @@ public void perform(Session session, String entityName, AuditConfiguration audit
}
@SuppressWarnings({"unchecked"})
- public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ public void performCollectionChange(Session session, String entityName, String propertyName, AuditConfiguration auditCfg,
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
final QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), "e");
// Adding a parameter for each id component, except the rev number
final String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
- final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
+ final Map<String, Object> data = persistentCollectionChangeData.getData();
+ final Map<String, Object> originalId = (Map<String, Object>) data.get(
originalIdPropName);
+
+
+ final CollectionPropertyMapper collectionPropertyMapper = (CollectionPropertyMapper) auditCfg.getEntCfg().get(entityName).getPropertyMapper().getMapper(propertyName);
+ final String revisionFieldName = auditCfg.getAuditEntCfg().getRevisionFieldName();
+ final String embeddableSetOrdinalPropertyName = auditCfg.getAuditEntCfg().getEmbeddableSetOrdinalPropertyName();
+ final String revisionTypePropName = auditCfg.getAuditEntCfg().getRevisionTypePropName();
+
for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
- if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
+ if (!revisionFieldName.equals(originalIdEntry.getKey()) && !embeddableSetOrdinalPropertyName.equals(originalIdEntry.getKey()) && !revisionTypePropName.equals(originalIdEntry.getKey())) {
qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
true, "=", originalIdEntry.getValue());
}
}
+
+ if(collectionPropertyMapper != null && collectionPropertyMapper.needsDataComparision())
+ {
+ for (Map.Entry<String, Object> dataEntry : data.entrySet()) {
+ if(!originalIdPropName.equals(dataEntry.getKey())) {
+ qb.getRootParameters().addWhereWithParam(dataEntry.getKey(),
+ true, "=", dataEntry.getValue());
+ }
+ }
+ }
addEndRevisionNullRestriction(auditCfg, qb);
@@ -112,7 +131,7 @@ public void performCollectionChange(Session session, AuditConfiguration auditCfg
}
// Save the audit data
- session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+ session.save(persistentCollectionChangeData.getEntityName(), data);
sessionCacheCleaner.scheduleAuditDataRemoval(session, persistentCollectionChangeData.getData());
}
@@ -132,7 +151,7 @@ public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryB
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
- String originalIdPropertyName, MiddleComponentData... componentDatas) {
+ String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
Parameters rootParameters = rootQueryBuilder.getRootParameters();
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
}
@@ -192,4 +211,3 @@ private void updateLastRevision(Session session, AuditConfiguration auditCfg, Li
}
}
}
-
View
4 ...in/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
@@ -53,7 +53,7 @@ public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor,
this.referencingPropertyName = referencingPropertyName;
collectionChanges = auditCfg.getEntCfg().get(getEntityName()).getPropertyMapper()
- .mapCollectionChanges(referencingPropertyName, collection, snapshot, id);
+ .mapCollectionChanges(sessionImplementor, referencingPropertyName, collection, snapshot, id);
}
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
@@ -83,7 +83,7 @@ public void perform(Session session, Object revisionData) {
((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName()))
.put(entitiesCfg.getRevisionFieldName(), revisionData);
- auditStrategy.performCollectionChange(session, verCfg, persistentCollectionChangeData, revisionData);
+ auditStrategy.performCollectionChange(session, getEntityName(), referencingPropertyName, verCfg, persistentCollectionChangeData, revisionData);
}
}
View
91 ...s/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableListEntity.java
@@ -0,0 +1,91 @@
+/*
+ * 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.entities.collection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OrderColumn;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.test.entities.components.Component3;
+
+/**
+ * @author Kristoffer Lundberg (kristoffer at cambio dot se)
+ */
+@Entity
+@Audited
+public class EmbeddableListEntity {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ @ElementCollection
+ @OrderColumn
+ private List<Component3> componentList = new ArrayList<Component3>();
+
+ public EmbeddableListEntity() {
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public List<Component3> getComponentList()
+ {
+ return componentList;
+ }
+
+ public void setComponentList(List<Component3> componentList)
+ {
+ this.componentList = componentList;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EmbeddableListEntity)) return false;
+
+ EmbeddableListEntity that = (EmbeddableListEntity) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (id != null ? id.hashCode() : 0);
+ }
+
+ public String toString() {
+ return "ECLE(id = " + id + ", componentList = " + componentList + ')';
+ }
+}
View
88 ...rs/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableMapEntity.java
@@ -0,0 +1,88 @@
+/*
+ * 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.entities.collection;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.test.entities.components.Component3;
+
+/**
+ * @author Kristoffer Lundberg (kristoffer at cambio dot se)
+ */
+@Entity
+public class EmbeddableMapEntity {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ @Audited
+ @ElementCollection
+ private Map<String, Component3> componentMap;
+
+ public EmbeddableMapEntity() {
+ componentMap = new HashMap<String, Component3>();
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Map<String, Component3> getComponentMap() {
+ return componentMap;
+ }
+
+ public void setComponentMap(Map<String, Component3> strings) {
+ this.componentMap = strings;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EmbeddableMapEntity)) return false;
+
+ EmbeddableMapEntity that = (EmbeddableMapEntity) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (id != null ? id.hashCode() : 0);
+ }
+
+ public String toString() {
+ return "EME(id = " + id + ", componentMap = " + componentMap + ")";
+ }
+}
View
89 ...rs/src/matrix/java/org/hibernate/envers/test/entities/collection/EmbeddableSetEntity.java
@@ -0,0 +1,89 @@
+/*
+ * 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.