From 99c13e596598574f2ca19689cf908fc48cd810b7 Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Sat, 18 Dec 2021 21:34:24 -0500 Subject: [PATCH] HHH-11595 Introduce `CollectionAuditTable` support --- .../userguide/chapters/envers/Envers.adoc | 3 ++ .../envers/CollectionAuditTable.java | 39 +++++++++++++++++++ .../metadata/AbstractMetadataGenerator.java | 4 +- ...iddleTableCollectionMetadataGenerator.java | 31 ++++++++++++--- .../reader/AuditedPropertiesReader.java | 9 +++++ .../metadata/reader/PropertyAuditingData.java | 10 +++++ 6 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 hibernate-envers/src/main/java/org/hibernate/envers/CollectionAuditTable.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc b/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc index ffa7d0ed0a..095e9a289c 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc @@ -350,6 +350,9 @@ It may be tedious to add this annotation to every audited entity, so if possible If you have a mapping with secondary tables, audit tables for them will be generated in the same way (by adding the prefix and suffix). If you wish to overwrite this behavior, you can use the `@SecondaryAuditTable` and `@SecondaryAuditTables` annotations. +If you have a mapping with collection tables, the audit table for them will be generated in the same way (by using the prefix and suffix). +If you wish to overwrite this behavior, you can use the `@CollectionAuditTable` annotations. + If you'd like to override auditing behavior of some fields/properties inherited from `@MappedSuperclass` or in an embedded component, you can apply the `@AuditOverride` annotation on the subtype or usage site of the component. diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/CollectionAuditTable.java b/hibernate-envers/src/main/java/org/hibernate/envers/CollectionAuditTable.java new file mode 100644 index 0000000000..a6c97e7e46 --- /dev/null +++ b/hibernate-envers/src/main/java/org/hibernate/envers/CollectionAuditTable.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.hibernate.Incubating; + +/** + * Allows for the customization of an Envers audit collection table. + * + * @author Chris Cranford + */ +@Incubating +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface CollectionAuditTable { + /** + * The name of the table + */ + String name(); + + /** + * The schema of the table. Defaults to the schema of the mapping. + */ + String schema() default ""; + + /** + * The catalog of the table. Defaults to the catalog of the mapping. + */ + String catalog() default ""; +} diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AbstractMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AbstractMetadataGenerator.java index 42710bf081..b124fb3b85 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AbstractMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AbstractMetadataGenerator.java @@ -80,7 +80,7 @@ public abstract class AbstractMetadataGenerator { protected String getSchemaName(String schemaFromAnnotation, Table table) { String schemaName = schemaFromAnnotation; - if ( StringTools.isEmpty(schemaName ) ) { + if ( StringTools.isEmpty( schemaName ) ) { schemaName = metadataBuildingContext.getConfiguration().getDefaultSchemaName(); if ( StringTools.isEmpty( schemaName ) ) { schemaName = table.getSchema(); @@ -91,7 +91,7 @@ public abstract class AbstractMetadataGenerator { protected String getCatalogName(String catalogFromAnnotation, Table table) { String catalogName = catalogFromAnnotation; - if ( StringTools.isEmpty(catalogName ) ) { + if ( StringTools.isEmpty( catalogName ) ) { catalogName = metadataBuildingContext.getConfiguration().getDefaultCatalogName(); if ( StringTools.isEmpty( catalogName ) ) { catalogName = table.getCatalog(); diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/MiddleTableCollectionMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/MiddleTableCollectionMetadataGenerator.java index 45ec0db1a5..33ecba26a4 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/MiddleTableCollectionMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/MiddleTableCollectionMetadataGenerator.java @@ -6,6 +6,7 @@ */ package org.hibernate.envers.configuration.internal.metadata; +import org.hibernate.envers.CollectionAuditTable; import org.hibernate.envers.boot.model.CompositeIdentifier; import org.hibernate.envers.boot.model.RootPersistentEntity; import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext; @@ -23,7 +24,6 @@ import org.hibernate.envers.internal.tools.StringTools; import org.hibernate.mapping.Collection; import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Table; import org.jboss.logging.Logger; @@ -194,17 +194,19 @@ public class MiddleTableCollectionMetadataGenerator extends AbstractCollectionMe ); } // Hibernate uses a middle table for mapping this relation, so we get its name directly. + CollectionAuditTable collectionAuditTable = context.getPropertyAuditingData().getCollectionAuditTable(); + if ( collectionAuditTable != null ) { + return collectionAuditTable.name(); + } return collection.getCollectionTable().getName(); } private RootPersistentEntity createMiddleEntity(CollectionMetadataContext context, String tableName, String entityName) { - final AuditJoinTableData joinTable = context.getPropertyAuditingData().getJoinTable(); - final Table collectionTable = context.getCollection().getCollectionTable(); final AuditTableData auditTableData = new AuditTableData( entityName, tableName, - getSchemaName( joinTable.getSchema(), collectionTable ), - getCatalogName( joinTable.getCatalog(), collectionTable ) + resolveSchema( context ), + resolveCatalog( context ) ); final RootPersistentEntity entity = new RootPersistentEntity( auditTableData, null ); @@ -229,6 +231,25 @@ public class MiddleTableCollectionMetadataGenerator extends AbstractCollectionMe return entity; } + private String resolveSchema(CollectionMetadataContext context) { + final CollectionAuditTable collectionAuditTable = context.getPropertyAuditingData().getCollectionAuditTable(); + if ( collectionAuditTable != null && !StringTools.isEmpty( collectionAuditTable.schema() ) ) { + return collectionAuditTable.schema(); + } + + final AuditJoinTableData joinTable = context.getPropertyAuditingData().getJoinTable(); + return getSchemaName( joinTable.getSchema(), context.getCollection().getCollectionTable() ); + } + + private String resolveCatalog(CollectionMetadataContext context) { + final CollectionAuditTable collectionAuditTable = context.getPropertyAuditingData().getCollectionAuditTable(); + if ( collectionAuditTable != null && !StringTools.isEmpty( collectionAuditTable.catalog() ) ) { + return collectionAuditTable.catalog(); + } + final AuditJoinTableData joinTable = context.getPropertyAuditingData().getJoinTable(); + return getCatalogName( joinTable.getCatalog(), context.getCollection().getCollectionTable() ); + } + private boolean isRevisionTypeInId(CollectionMetadataContext context) { return isEmbeddableElementType( context ) || isLobMapElementType( context ); } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java index 557033ab9a..f5f8b66b1a 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/AuditedPropertiesReader.java @@ -32,6 +32,7 @@ import org.hibernate.envers.AuditMappedBy; import org.hibernate.envers.AuditOverride; import org.hibernate.envers.AuditOverrides; import org.hibernate.envers.Audited; +import org.hibernate.envers.CollectionAuditTable; import org.hibernate.envers.NotAudited; import org.hibernate.envers.RelationTargetAuditMode; import org.hibernate.envers.RelationTargetNotFoundAction; @@ -540,6 +541,7 @@ public class AuditedPropertiesReader { propertyData.setAccessType( accessType ); addPropertyJoinTables( property, propertyData ); + addPropertyCollectionAuditTable( property, propertyData ); addPropertyAuditingOverrides( property, propertyData ); if ( !processPropertyAuditingOverrides( property, propertyData ) ) { // not audited due to AuditOverride annotation @@ -677,6 +679,13 @@ public class AuditedPropertiesReader { } } + private void addPropertyCollectionAuditTable(XProperty property, PropertyAuditingData propertyAuditingData) { + final CollectionAuditTable collectionAuditTableAnn = property.getAnnotation( CollectionAuditTable.class ); + if ( collectionAuditTableAnn != null ) { + propertyAuditingData.setCollectionAuditTable( collectionAuditTableAnn ); + } + } + /** * Add the {@link AuditOverride} annotations. * diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/PropertyAuditingData.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/PropertyAuditingData.java index 0b746e0f65..7dc16e4a75 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/PropertyAuditingData.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/reader/PropertyAuditingData.java @@ -14,6 +14,7 @@ import jakarta.persistence.EnumType; import org.hibernate.envers.AuditOverride; import org.hibernate.envers.AuditOverrides; +import org.hibernate.envers.CollectionAuditTable; import org.hibernate.envers.RelationTargetAuditMode; import org.hibernate.envers.RelationTargetNotFoundAction; import org.hibernate.envers.internal.entities.PropertyData; @@ -33,6 +34,7 @@ public class PropertyAuditingData { private String beanName; private String mapKey; private EnumType mapKeyEnumType; + private CollectionAuditTable collectionAuditTable; private AuditJoinTableData joinTable; private String accessType; private final List auditJoinTableOverrides = new ArrayList<>( 0 ); @@ -329,6 +331,14 @@ public class PropertyAuditingData { this.virtualPropertyType = virtualPropertyType; } + public CollectionAuditTable getCollectionAuditTable() { + return collectionAuditTable; + } + + public void setCollectionAuditTable(CollectionAuditTable collectionAuditTable) { + this.collectionAuditTable = collectionAuditTable; + } + public PropertyData resolvePropertyData() { if ( propertyType != null && virtualPropertyType != null ) { return new PropertyData(