HHH-9108 - Fix PropertyAccessException when auditing an Embeddable that contains an associative collection.
This commit is contained in:
parent
61ce4b86ff
commit
652f85644f
|
@ -14,10 +14,13 @@ import java.util.Map;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.envers.ModificationStore;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.AuditedPropertiesHolder;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.ClassAuditingData;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
|
||||
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
||||
import org.hibernate.envers.internal.EnversMessageLogger;
|
||||
import org.hibernate.envers.internal.tools.MappingTools;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.List;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
||||
|
@ -78,31 +81,26 @@ public class ClassesAuditingData {
|
|||
for ( Map.Entry<PersistentClass, ClassAuditingData> classAuditingDataEntry : persistentClassToAuditingData.entrySet() ) {
|
||||
final PersistentClass pc = classAuditingDataEntry.getKey();
|
||||
final ClassAuditingData classAuditingData = classAuditingDataEntry.getValue();
|
||||
for ( String propertyName : classAuditingData.getPropertyNames() ) {
|
||||
updateCalculatedProperty( pc, classAuditingData, propertyName );
|
||||
for ( String propertyName : classAuditingData.getNonSyntheticPropertyNames() ) {
|
||||
final Property property = pc.getProperty( propertyName );
|
||||
updateCalculatedProperty( pc.getEntityName(), property, propertyName, classAuditingData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCalculatedProperty(
|
||||
PersistentClass pc,
|
||||
ClassAuditingData classAuditingData,
|
||||
String propertyName) {
|
||||
|
||||
final PropertyAuditingData propertyAuditingData = classAuditingData.getPropertyAuditingData( propertyName );
|
||||
|
||||
private void updateCalculatedProperty(String entityName, Property property, String propertyName, AuditedPropertiesHolder propertyHolder) {
|
||||
final PropertyAuditingData propertyAuditingData = propertyHolder.getPropertyAuditingData( propertyName );
|
||||
final boolean isAuditMappedBy = propertyAuditingData.getAuditMappedBy() != null;
|
||||
final boolean isRelationMappedBy = propertyAuditingData.getRelationMappedBy() != null;
|
||||
|
||||
// handle updating the property, if applicable.
|
||||
if ( isAuditMappedBy || isRelationMappedBy ) {
|
||||
final Property property = pc.getProperty( propertyName );
|
||||
final String referencedEntityName = MappingTools.getReferencedEntityName( property.getValue() );
|
||||
|
||||
final ClassAuditingData referencedAuditData = entityNameToAuditingData.get( referencedEntityName );
|
||||
|
||||
if ( isAuditMappedBy ) {
|
||||
// If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable.
|
||||
setAuditMappedByInsertable( referencedEntityName, pc.getEntityName(), referencedAuditData, propertyAuditingData );
|
||||
setAuditMappedByInsertable( referencedEntityName, entityName, referencedAuditData, propertyAuditingData );
|
||||
}
|
||||
else if ( isRelationMappedBy && ( property.getValue() instanceof List ) ) {
|
||||
// If a property has mappedBy= and @Indexed and isn't @AuditMappedBy, add synthetic support.
|
||||
|
@ -113,6 +111,18 @@ public class ClassesAuditingData {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// HHH-9108
|
||||
// Added support to handle nested property calculations for components.
|
||||
// This is useful for AuditMappedBy inside an Embeddable that holds a collection of entities.
|
||||
if ( propertyAuditingData instanceof ComponentAuditingData ) {
|
||||
final ComponentAuditingData componentAuditingData = ( ComponentAuditingData) propertyAuditingData;
|
||||
final Component component = (Component) property.getValue();
|
||||
for ( String componentPropertyName : componentAuditingData.getNonSyntheticPropertyNames() ) {
|
||||
final Property componentProperty = component.getProperty( componentPropertyName );
|
||||
updateCalculatedProperty( entityName, componentProperty, componentPropertyName, componentAuditingData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setAuditMappedByInsertable(
|
||||
|
|
|
@ -80,6 +80,13 @@ public class ClassAuditingData implements AuditedPropertiesHolder {
|
|||
return properties.containsKey( propertyName );
|
||||
}
|
||||
|
||||
public Iterable<String> getNonSyntheticPropertyNames() {
|
||||
return properties.entrySet().stream()
|
||||
.filter( e -> !e.getValue().isSyntheic() )
|
||||
.map( Map.Entry::getKey )
|
||||
.collect( Collectors.toList() );
|
||||
}
|
||||
|
||||
public Iterable<PropertyAuditingData> getSyntheticProperties() {
|
||||
return properties.values().stream()
|
||||
.filter( p -> p.isSyntheic() )
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.envers.configuration.internal.metadata.reader;
|
|||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
||||
|
||||
|
@ -16,6 +17,7 @@ import static org.hibernate.envers.internal.tools.Tools.newHashMap;
|
|||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Hern&aacut;n Chanfreau
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class ComponentAuditingData extends PropertyAuditingData implements AuditedPropertiesHolder {
|
||||
private final Map<String, PropertyAuditingData> properties;
|
||||
|
@ -47,4 +49,12 @@ public class ComponentAuditingData extends PropertyAuditingData implements Audit
|
|||
public Set<String> getPropertyNames() {
|
||||
return properties.keySet();
|
||||
}
|
||||
|
||||
public Iterable<String> getNonSyntheticPropertyNames() {
|
||||
return properties.entrySet().stream()
|
||||
.filter( e -> !e.getValue().isSyntheic() )
|
||||
.map( Map.Entry::getKey )
|
||||
.collect( Collectors.toList() );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -162,14 +162,22 @@ public abstract class BaseEnversCollectionEventListener extends BaseEnversEventL
|
|||
*/
|
||||
private RelationDescription searchForRelationDescription(String entityName, String referencingPropertyName) {
|
||||
final EntityConfiguration configuration = getEnversService().getEntitiesConfigurations().get( entityName );
|
||||
final RelationDescription rd = configuration.getRelationDescription( referencingPropertyName );
|
||||
final String propertyName = sanitizeReferencingPropertyName( referencingPropertyName );
|
||||
final RelationDescription rd = configuration.getRelationDescription( propertyName );
|
||||
if ( rd == null && configuration.getParentEntityName() != null ) {
|
||||
return searchForRelationDescription( configuration.getParentEntityName(), referencingPropertyName );
|
||||
return searchForRelationDescription( configuration.getParentEntityName(), propertyName );
|
||||
}
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
private String sanitizeReferencingPropertyName(String propertyName) {
|
||||
if ( propertyName != null && propertyName.indexOf( '.' ) != -1 ) {
|
||||
return propertyName.replaceAll( "\\.", "\\_" );
|
||||
}
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
private void generateFakeBidirecationalRelationWorkUnits(
|
||||
AuditProcess auditProcess,
|
||||
PersistentCollection newColl,
|
||||
|
|
Loading…
Reference in New Issue