This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch 8.0.x-hibernate7
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 20762d8e0db9d93d375a0f10eecef313291e9e2e
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Sat Feb 14 22:13:17 2026 -0600

    Refactor multi-tenant filter binding to dedicated class
    
    - Extract filter logic to MultiTenantFilterBinder for better modularity.
    - Improve shouldApplyFilter for Hibernate 7 class and proxy compatibility.
    - Update tests and dependencies to support Hibernate 7 mapping models.
---
 grails-data-hibernate7/core/build.gradle           |   1 +
 .../orm/hibernate/cfg/GrailsDomainBinder.java      |  78 ++--------
 .../util/MultiTenantFilterBinder.java              | 117 ++++++++++++++
 .../util/MultiTenantFilterBinderSpec.groovy        | 168 +++++++++++++++++++++
 4 files changed, 299 insertions(+), 65 deletions(-)

diff --git a/grails-data-hibernate7/core/build.gradle 
b/grails-data-hibernate7/core/build.gradle
index 9ba23bd2bb..5bf342dcf8 100644
--- a/grails-data-hibernate7/core/build.gradle
+++ b/grails-data-hibernate7/core/build.gradle
@@ -56,6 +56,7 @@ dependencies {
         exclude group:'org.slf4j', module:'slf4j-log4j12'
         exclude group:'xml-apis', module:'xml-apis'
     }
+    api "org.hibernate.models:hibernate-models:1.0.0"
     api 'org.hibernate.validator:hibernate-validator', {
         exclude group:'commons-logging', module:'commons-logging'
         exclude group:'commons-collections', module:'commons-collections'
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index e1588603a8..6392fd1a42 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -45,6 +45,7 @@ import 
org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolde
 import org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionBinder;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterBinder;
 import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
 import 
org.grails.orm.hibernate.cfg.domainbinding.util.ForeignKeyColumnCountCalculator;
 import org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyWrapper;
@@ -226,12 +227,13 @@ public class GrailsDomainBinder
         SimpleIdBinder simpleIdBinder = new 
SimpleIdBinder(metadataBuildingContext, namingStrategy, jdbcEnvironment, new 
BasicValueIdCreator(jdbcEnvironment), simpleValueBinder, propertyBinder);
         IdentityBinder identityBinder = new IdentityBinder(simpleIdBinder, 
compositeIdBinder);
         VersionBinder versionBinder = new 
VersionBinder(metadataBuildingContext, simpleValueBinder, propertyBinder, 
BasicValue::new);
+        MultiTenantFilterBinder multiTenantFilterBinder = new 
MultiTenantFilterBinder();
 
         hibernateMappingContext
                 .getHibernatePersistentEntities(dataSourceName)
                 .stream()
                 .filter(persistentEntity -> 
persistentEntity.forGrailsDomainMapping(dataSourceName))
-                .forEach(hibernatePersistentEntity -> 
bindRoot(hibernatePersistentEntity, metadataCollector, sessionFactoryName, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, identityBinder, 
versionBinder, grailsPropertyBinder, classBinder, propertyFromValueCreator));
+                .forEach(hibernatePersistentEntity -> 
bindRoot(hibernatePersistentEntity, metadataCollector, sessionFactoryName, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, identityBinder, 
versionBinder, grailsPropertyBinder, classBinder, propertyFromValueCreator, 
multiTenantFilterBinder));
     }
 
 
@@ -262,7 +264,7 @@ public class GrailsDomainBinder
      * @param mappings    The Hibernate Mappings object
      * @param sessionFactoryBeanName  the session factory bean name
      */
-    protected void bindRoot(@Nonnull GrailsHibernatePersistentEntity 
entity,@Nonnull InFlightMetadataCollector mappings, String 
sessionFactoryBeanName, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
IdentityBinder identityBinder, VersionBinder versionBinder, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator) {
+    protected void bindRoot(@Nonnull GrailsHibernatePersistentEntity 
entity,@Nonnull InFlightMetadataCollector mappings, String 
sessionFactoryBeanName, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
IdentityBinder identityBinder, VersionBinder versionBinder, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenantFi [...]
         if (mappings.getEntityBinding(entity.getName()) != null) {
             LOG.info("[GrailsDomainBinder] Class [" + entity.getName() + "] is 
already mapped, skipping.. ");
             return;
@@ -279,10 +281,10 @@ public class GrailsDomainBinder
                 bindDiscriminatorProperty(root.getTable(), root, m);
             }
             // bind the sub classes
-            children.forEach(sub -> bindSubClass(sub, root, mappings, 
sessionFactoryBeanName, finalMapping,mappingCacheHolder, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, 
grailsPropertyBinder, classBinder, propertyFromValueCreator ));
+            children.forEach(sub -> bindSubClass(sub, root, mappings, 
sessionFactoryBeanName, finalMapping,mappingCacheHolder, 
defaultColumnNameFetcher, columnNameForPropertyAndPathFetcher, 
grailsPropertyBinder, classBinder, propertyFromValueCreator, 
multiTenantFilterBinder ));
         }
 
-        addMultiTenantFilterIfNecessary(entity, root, mappings, 
defaultColumnNameFetcher);
+        multiTenantFilterBinder.addMultiTenantFilterIfNecessary(entity, root, 
mappings, defaultColumnNameFetcher);
 
         mappings.addEntityBinding(root);
     }
@@ -296,47 +298,6 @@ public class GrailsDomainBinder
         return namingStrategy;
     }
 
-    /**
-     * Add a Hibernate filter for multitenancy if the persistent class is 
multitenant
-     *
-     * @param entity          target persistent entity for get tenant 
information
-     * @param persistentClass persistent class for add the filter and get 
tenant property info
-     * @param mappings        mappings to add the filter
-     */
-    private void addMultiTenantFilterIfNecessary(
-            @Nonnull GrailsHibernatePersistentEntity entity, PersistentClass 
persistentClass,
-            @Nonnull InFlightMetadataCollector mappings, 
DefaultColumnNameFetcher defaultColumnNameFetcher) {
-
-        if (entity.isMultiTenant()) {
-            TenantId tenantId = entity.getTenantId();
-
-            if (tenantId != null) {
-                String filterCondition = 
entity.getMultiTenantFilterCondition(defaultColumnNameFetcher);
-
-                persistentClass.addFilter(
-                        GormProperties.TENANT_IDENTITY,
-                        filterCondition,
-                        true,
-                        Collections.emptyMap(),
-                        Collections.emptyMap()
-                );
-
-                Property property = getProperty(persistentClass, 
tenantId.getName());
-                if (property.getValue() instanceof BasicValue basicValue) {
-                    JdbcMapping jdbcMapping = 
basicValue.resolve().getJdbcMapping();
-                    var stringVMap = 
Collections.singletonMap(GormProperties.TENANT_IDENTITY, jdbcMapping);
-                    FilterDefinition definition = new FilterDefinition(
-                            GormProperties.TENANT_IDENTITY,
-                            filterCondition,
-                            stringVMap
-                    );
-                    mappings.addFilterDefinition(definition);
-                }
-            }
-        }
-    }
-
-
     /**
      * Binds a sub class.
      *
@@ -350,24 +311,24 @@ public class GrailsDomainBinder
                               PersistentClass parent,
                               @Nonnull InFlightMetadataCollector mappings,
                               String sessionFactoryBeanName
-                            , Mapping m, MappingCacheHolder 
mappingCacheHolder, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator) {
+                            , Mapping m, MappingCacheHolder 
mappingCacheHolder, DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenantFilterBinder) {
         mappingCacheHolder.cacheMapping(sub);
-        Subclass subClass = createSubclassMapping(sub, parent, mappings, 
sessionFactoryBeanName, m, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator);
+        Subclass subClass = createSubclassMapping(sub, parent, mappings, 
sessionFactoryBeanName, m, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator, multiTenantFilterBinder);
 
 
         parent.addSubclass(subClass);
         mappings.addEntityBinding(subClass);
 
-        addMultiTenantFilterIfNecessary(sub, subClass, mappings, 
defaultColumnNameFetcher);
+        multiTenantFilterBinder.addMultiTenantFilterIfNecessary(sub, subClass, 
mappings, defaultColumnNameFetcher);
 
         var children = sub.getChildEntities(dataSourceName);
         if (!children.isEmpty()) {
             // bind the sub classes
-            children.forEach(sub1 -> bindSubClass(sub1, subClass, mappings, 
sessionFactoryBeanName, m,mappingCacheHolder, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator ));
+            children.forEach(sub1 -> bindSubClass(sub1, subClass, mappings, 
sessionFactoryBeanName, m,mappingCacheHolder, defaultColumnNameFetcher, 
columnNameForPropertyAndPathFetcher, grailsPropertyBinder, classBinder, 
propertyFromValueCreator, multiTenantFilterBinder ));
         }
     }
 
-    private @NonNull Subclass createSubclassMapping(@NonNull 
GrailsHibernatePersistentEntity subEntity, PersistentClass parent, @NonNull 
InFlightMetadataCollector mappings, String sessionFactoryBeanName, Mapping m, 
DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator) {
+    private @NonNull Subclass createSubclassMapping(@NonNull 
GrailsHibernatePersistentEntity subEntity, PersistentClass parent, @NonNull 
InFlightMetadataCollector mappings, String sessionFactoryBeanName, Mapping m, 
DefaultColumnNameFetcher defaultColumnNameFetcher, 
ColumnNameForPropertyAndPathFetcher columnNameForPropertyAndPathFetcher, 
GrailsPropertyBinder grailsPropertyBinder, ClassBinder classBinder, 
PropertyFromValueCreator propertyFromValueCreator, MultiTenantFilterBinder 
multiTenan [...]
         Subclass subClass;
         subEntity.configureDerivedProperties();
         if (!m.getTablePerHierarchy() && !m.isTablePerConcreteClass()) {
@@ -381,7 +342,7 @@ public class GrailsDomainBinder
         else {
             subClass = new SingleTableSubclass(parent, 
this.metadataBuildingContext);
             subClass.setDiscriminatorValue(subEntity.getDiscriminatorValue());
-            bindSubClass(subEntity, subClass, mappings, 
sessionFactoryBeanName, defaultColumnNameFetcher, grailsPropertyBinder, 
classBinder, propertyFromValueCreator);
+            bindSubClass(subEntity, subClass, mappings, 
sessionFactoryBeanName, defaultColumnNameFetcher, grailsPropertyBinder, 
classBinder, propertyFromValueCreator, multiTenantFilterBinder);
         }
         
subClass.setBatchSize(Optional.ofNullable(m.getBatchSize()).orElse(-1));
         subClass.setDynamicUpdate(m.getDynamicUpdate());
@@ -480,7 +441,7 @@ public class GrailsDomainBinder
      * @param mappings The mappings instance
      */
     private void bindSubClass(@Nonnull GrailsHibernatePersistentEntity sub, 
Subclass subClass, @Nonnull InFlightMetadataCollector mappings,
-                                String sessionFactoryBeanName, 
DefaultColumnNameFetcher defaultColumnNameFetcher, GrailsPropertyBinder 
grailsPropertyBinder, ClassBinder classBinder, PropertyFromValueCreator 
propertyFromValueCreator) {
+                                String sessionFactoryBeanName, 
DefaultColumnNameFetcher defaultColumnNameFetcher, GrailsPropertyBinder 
grailsPropertyBinder, ClassBinder classBinder, PropertyFromValueCreator 
propertyFromValueCreator, MultiTenantFilterBinder multiTenantFilterBinder) {
         classBinder.bindClass(sub, subClass, mappings);
 
         if (LOG.isDebugEnabled())
@@ -653,17 +614,4 @@ public class GrailsDomainBinder
     public void contribute(TypeContributions typeContributions, 
ServiceRegistry serviceRegistry) {
 
     }
-
-    private Property getProperty(PersistentClass associatedClass, String 
propertyName) throws MappingException {
-        try {
-            return associatedClass.getProperty(propertyName);
-        }
-        catch (MappingException e) {
-            //maybe it's squirreled away in a composite primary key
-            if (associatedClass.getKey() instanceof Component) {
-                return ((Component) 
associatedClass.getKey()).getProperty(propertyName);
-            }
-            throw e;
-        }
-    }
 }
\ No newline at end of file
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinder.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinder.java
new file mode 100644
index 0000000000..a74d51f0bb
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinder.java
@@ -0,0 +1,117 @@
+package org.grails.orm.hibernate.cfg.domainbinding.util;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.MappingException;
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.metamodel.mapping.JdbcMapping;
+import org.hibernate.engine.spi.FilterDefinition;
+import org.hibernate.mapping.BasicValue;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.RootClass;
+
+import org.grails.datastore.mapping.model.config.GormProperties;
+import org.grails.datastore.mapping.model.types.TenantId;
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity;
+
+/**
+ * Utility class for binding multi-tenant filters to the Hibernate meta model.
+ *
+ * @author Walter Duque de Estrada
+ * @author Graeme Rocher
+ * @since 7.0
+ */
+public class MultiTenantFilterBinder {
+
+    /**
+     * Adds a multi-tenant filter to the given persistent class if necessary.
+     *
+     * @param entity          The target persistent entity
+     * @param persistentClass The persistent class to add the filter to
+     * @param mappings        The in-flight metadata collector
+     * @param fetcher         The column name fetcher
+     */
+    public void addMultiTenantFilterIfNecessary(
+            @Nonnull GrailsHibernatePersistentEntity entity,
+            @Nonnull PersistentClass persistentClass,
+            @Nonnull InFlightMetadataCollector mappings,
+            @Nonnull DefaultColumnNameFetcher fetcher) {
+
+        if (!entity.isMultiTenant()) {
+            return;
+        }
+
+        Optional.ofNullable(entity.getTenantId())
+                .map(TenantId::getName)
+                .map(name -> getProperty(persistentClass, name))
+                .ifPresent(property -> {
+                    var filterName = GormProperties.TENANT_IDENTITY;
+                    ensureGlobalFilterDefinition(mappings, filterName, 
property);
+                    applyFilterToPersistentClass(entity, persistentClass, 
fetcher, filterName, property);
+                });
+    }
+
+    private void ensureGlobalFilterDefinition(InFlightMetadataCollector 
mappings, String filterName, Property property) {
+        if (mappings.getFilterDefinition(filterName) == null && 
property.getValue() instanceof BasicValue basicValue) {
+            JdbcMapping jdbcMapping = basicValue.resolve().getJdbcMapping();
+            mappings.addFilterDefinition(new FilterDefinition(
+                    filterName,
+                    null, // No default condition; let classes specify their 
own
+                    Collections.singletonMap(filterName, jdbcMapping)
+            ));
+        }
+    }
+
+    private void applyFilterToPersistentClass(
+            GrailsHibernatePersistentEntity entity,
+            PersistentClass persistentClass,
+            DefaultColumnNameFetcher fetcher,
+            String filterName,
+            Property property) {
+
+        if (shouldApplyFilter(entity, persistentClass, property)) {
+            persistentClass.addFilter(
+                    filterName,
+                    entity.getMultiTenantFilterCondition(fetcher),
+                    true, // autoAliasInjection
+                    Collections.emptyMap(),
+                    Collections.emptyMap()
+            );
+        }
+    }
+
+    private boolean shouldApplyFilter(GrailsHibernatePersistentEntity entity, 
PersistentClass persistentClass, Property property) {
+        boolean isRoot = persistentClass instanceof RootClass || 
persistentClass.equals(persistentClass.getRootClass());
+        
+        var table = persistentClass.getTable();
+        var propertyValue = property.getValue();
+        var propertyTable = propertyValue != null ? propertyValue.getTable() : 
null;
+
+        boolean isInherited = table != null && propertyTable != null && 
!table.equals(propertyTable);
+
+        // Apply if it's the root or if the subclass has its own table 
containing the column (UnionSubclass).
+        // Skip if it's a SingleTable subclass (redundant) or JoinedSubclass 
where column is in root (alias safety).
+        if (isRoot || !isInherited) {
+            return isRoot || !entity.isTablePerHierarchySubclass();
+        }
+        return false;
+    }
+
+    private Property getProperty(PersistentClass associatedClass, String 
propertyName) {
+        try {
+            return associatedClass.getProperty(propertyName);
+        }
+        catch (MappingException e) {
+            // maybe it's squirreled away in a composite primary key
+            if (associatedClass.getKey() instanceof Component component) {
+                return component.getProperty(propertyName);
+            }
+            return null;
+        }
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinderSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinderSpec.groovy
new file mode 100644
index 0000000000..58de04027b
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/MultiTenantFilterBinderSpec.groovy
@@ -0,0 +1,168 @@
+package org.grails.orm.hibernate.cfg.domainbinding.util
+
+import grails.gorm.specs.HibernateGormDatastoreSpec
+import org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterBinder
+import org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher
+import org.grails.datastore.mapping.model.config.GormProperties
+import org.grails.orm.hibernate.cfg.GrailsHibernatePersistentEntity
+import org.hibernate.boot.spi.InFlightMetadataCollector
+import org.hibernate.mapping.BasicValue
+import org.hibernate.mapping.PersistentClass
+import org.hibernate.mapping.Property
+import org.hibernate.mapping.RootClass
+import org.hibernate.mapping.SingleTableSubclass
+import org.hibernate.mapping.JoinedSubclass
+import org.hibernate.mapping.UnionSubclass
+import org.hibernate.mapping.Table
+import org.hibernate.metamodel.mapping.JdbcMapping
+import org.hibernate.engine.spi.FilterDefinition
+import org.grails.datastore.mapping.model.types.TenantId
+import spock.lang.Specification
+
+/**
+ * Tests for MultiTenantFilterBinder.
+ */
+class MultiTenantFilterBinderSpec extends HibernateGormDatastoreSpec {
+
+    MultiTenantFilterBinder filterBinder = new MultiTenantFilterBinder()
+    DefaultColumnNameFetcher fetcher = Mock(DefaultColumnNameFetcher)
+    InFlightMetadataCollector mockCollector = 
GroovyMock(InFlightMetadataCollector)
+
+    void "test add multi tenant filter to root class"() {
+        given:
+        def entity = Mock(GrailsHibernatePersistentEntity)
+        def buildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        def persistentClass = new RootClass(buildingContext)
+        
+        def tenantId = Mock(TenantId)
+        def property = new Property()
+        property.setName("tenantId")
+        
+        def table = new Table("ROOT_TABLE")
+        def value = new BasicValue(buildingContext, table)
+        value.setTypeName("long")
+        
+        entity.isMultiTenant() >> true
+        entity.getTenantId() >> tenantId
+        tenantId.getName() >> "tenantId"
+        
+        property.setValue(value)
+        persistentClass.setTable(table)
+        persistentClass.addProperty(property)
+        
+        // Setup for FilterDefinition
+        mockCollector.getFilterDefinition(GormProperties.TENANT_IDENTITY) >> 
null
+        
+        entity.getMultiTenantFilterCondition(fetcher) >> "tenant_id = 
:tenantId"
+
+        when:
+        filterBinder.addMultiTenantFilterIfNecessary(entity, persistentClass, 
mockCollector, fetcher)
+
+        then:
+        1 * mockCollector.addFilterDefinition(_ as FilterDefinition)
+        persistentClass.getFilters().any { it.getName() == 
GormProperties.TENANT_IDENTITY && it.getCondition() == "tenant_id = :tenantId" }
+    }
+
+    void "test skip filter for single table subclass (redundant)"() {
+        given:
+        def entity = Mock(GrailsHibernatePersistentEntity)
+        def buildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        def rootClass = new RootClass(buildingContext)
+        def table = new Table("ROOT_TABLE")
+        rootClass.setTable(table)
+        
+        def persistentClass = new SingleTableSubclass(rootClass, 
buildingContext)
+        def tenantId = Mock(TenantId)
+        
+        def property = new Property()
+        property.setName("tenantId")
+        def value = new BasicValue(buildingContext, table)
+        value.setTypeName("long")
+        property.setValue(value)
+        
+        rootClass.addProperty(property)
+        
+        entity.isMultiTenant() >> true
+        entity.getTenantId() >> tenantId
+        tenantId.getName() >> "tenantId"
+        
+        entity.isTablePerHierarchySubclass() >> true
+        mockCollector.getFilterDefinition(_) >> Mock(FilterDefinition)
+
+        when:
+        filterBinder.addMultiTenantFilterIfNecessary(entity, persistentClass, 
mockCollector, fetcher)
+
+        then:
+        !persistentClass.getFilters().any { it.getName() == 
GormProperties.TENANT_IDENTITY }
+    }
+
+    void "test skip filter for joined subclass if inherited (alias safety)"() {
+        given:
+        def entity = Mock(GrailsHibernatePersistentEntity)
+        def buildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        def rootClass = new RootClass(buildingContext)
+        def rootTable = new Table("ROOT_TABLE")
+        rootTable.setName("ROOT_TABLE")
+        rootClass.setTable(rootTable)
+
+        def persistentClass = new JoinedSubclass(rootClass, buildingContext)
+        def subTable = new Table("SUB_TABLE")
+        subTable.setName("SUB_TABLE")
+        persistentClass.setTable(subTable)
+        
+        def tenantId = Mock(TenantId)
+        def property = new Property()
+        property.setName("tenantId")
+        def value = new BasicValue(buildingContext, rootTable)
+        value.setTypeName("long")
+        property.setValue(value)
+        
+        rootClass.addProperty(property)
+
+        entity.isMultiTenant() >> true
+        entity.getTenantId() >> tenantId
+        tenantId.getName() >> "tenantId"
+        
+        mockCollector.getFilterDefinition(_) >> Mock(FilterDefinition)
+
+        when:
+        filterBinder.addMultiTenantFilterIfNecessary(entity, persistentClass, 
mockCollector, fetcher)
+
+        then:
+        !persistentClass.getFilters().any { it.getName() == 
GormProperties.TENANT_IDENTITY }
+    }
+
+    void "test add filter for union subclass (own table)"() {
+        given:
+        def entity = Mock(GrailsHibernatePersistentEntity)
+        def buildingContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        def rootClass = new RootClass(buildingContext)
+        def subTable = new Table("SUB_TABLE")
+
+        def persistentClass = new UnionSubclass(rootClass, buildingContext)
+        persistentClass.setTable(subTable)
+        
+        def tenantId = Mock(TenantId)
+        def property = new Property()
+        property.setName("tenantId")
+        def value = new BasicValue(buildingContext, subTable)
+        value.setTypeName("long")
+        property.setValue(value)
+        
+        persistentClass.addProperty(property)
+
+        entity.isMultiTenant() >> true
+        entity.getTenantId() >> tenantId
+        tenantId.getName() >> "tenantId"
+        
+        entity.isTablePerHierarchySubclass() >> false
+        mockCollector.getFilterDefinition(_) >> Mock(FilterDefinition)
+        entity.getMultiTenantFilterCondition(fetcher) >> "tenant_id = 
:tenantId"
+
+        when:
+        filterBinder.addMultiTenantFilterIfNecessary(entity, persistentClass, 
mockCollector, fetcher)
+
+        then:
+        persistentClass.getFilters().any { it.getName() == 
GormProperties.TENANT_IDENTITY && it.getCondition() == "tenant_id = :tenantId" }
+    }
+}

Reply via email to