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 da0b6fa09852e279c86fc407551af83c6646bf2b Author: Walter Duque de Estrada <[email protected]> AuthorDate: Wed Feb 11 19:15:51 2026 -0600 updated HibernateMappingContext to inject the dataSourceName into GrailsHibernatePersistentEntity when calling getHibernatePersistentEntities(String dataSourceName). This involved: 1. Adding setDataSourceName and getDataSourceName to the GrailsHibernatePersistentEntity interface. 2. Implementing these methods in HibernatePersistentEntity and HibernateEmbeddedPersistentEntity. 3. Modifying HibernateMappingContext.getHibernatePersistentEntities to accept the dataSourceName and inject it into each entity. 4. Updating GrailsDomainBinder to pass the dataSourceName to getHibernatePersistentEntities. 5. Adding a test case to GrailsHibernatePersistentEntitySpec to verify the injection. --- .../orm/hibernate/cfg/GrailsDomainBinder.java | 6 +- .../cfg/GrailsHibernatePersistentEntity.java | 24 ++ .../cfg/HibernateEmbeddedPersistentEntity.java | 11 + .../orm/hibernate/cfg/HibernateMappingContext.java | 4 +- .../hibernate/cfg/HibernatePersistentEntity.java | 11 + .../secondpass/CollectionSecondPassBinder.java | 29 +-- .../cfg/GrailsHibernatePersistentEntitySpec.groovy | 258 +++++++++++++++++++++ 7 files changed, 311 insertions(+), 32 deletions(-) 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 a88c0b8695..05e961115e 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 @@ -135,7 +135,7 @@ public class GrailsDomainBinder this.mappingCacheHolder = MappingCacheHolder.getInstance(); this.collectionHolder = new CollectionHolder(this); // pre-build mappings - for (GrailsHibernatePersistentEntity persistentEntity : hibernateMappingContext.getHibernatePersistentEntities()) { + for (GrailsHibernatePersistentEntity persistentEntity : hibernateMappingContext.getHibernatePersistentEntities(dataSourceName)) { mappingCacheHolder.cacheMapping(persistentEntity); } } @@ -176,7 +176,9 @@ public class GrailsDomainBinder this.identityBinder = new IdentityBinder(metadataBuildingContext, getNamingStrategy(), getJdbcEnvironment(), compositeIdBinder); this.versionBinder = new VersionBinder(metadataBuildingContext, getNamingStrategy()); - hibernateMappingContext.getHibernatePersistentEntities().stream() + hibernateMappingContext + .getHibernatePersistentEntities(dataSourceName) + .stream() .filter(persistentEntity -> persistentEntity.forGrailsDomainMapping(dataSourceName)) .forEach(hibernatePersistentEntity -> bindRoot(hibernatePersistentEntity, metadataCollector, sessionFactoryName)); } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntity.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntity.java index c7d647f7f3..1e59ac83cd 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntity.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntity.java @@ -35,6 +35,28 @@ public interface GrailsHibernatePersistentEntity extends PersistentEntity { return !this.isRoot() && (rootMapping == null || rootMapping.getTablePerHierarchy()); } + default java.util.Set<String> buildDiscriminatorSet() { + java.util.Set<String> theSet = new java.util.HashSet<>(); + + String discriminator = getDiscriminatorValue(); + Mapping rootMapping = getRootMapping(); + String quote = "'"; + if (rootMapping != null && rootMapping.getDatasources() != null) { + DiscriminatorConfig discriminatorConfig = rootMapping.getDiscriminator(); + if(discriminatorConfig != null && discriminatorConfig.getType() != null && !discriminatorConfig.getType().equals("string")) + quote = ""; + } + theSet.add(quote + discriminator + quote); + + final java.util.Collection<PersistentEntity> childEntities = getMappingContext().getDirectChildEntities(this); + for (PersistentEntity subClass : childEntities) { + if (subClass instanceof GrailsHibernatePersistentEntity) { + theSet.addAll(((GrailsHibernatePersistentEntity) subClass).buildDiscriminatorSet()); + } + } + return theSet; + } + @Override GrailsHibernatePersistentProperty getIdentity(); @@ -49,7 +71,9 @@ public interface GrailsHibernatePersistentEntity extends PersistentEntity { } + void setDataSourceName(String dataSourceName); + String getDataSourceName(); boolean forGrailsDomainMapping(String dataSourceName); diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateEmbeddedPersistentEntity.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateEmbeddedPersistentEntity.java index ba076d649a..8875d00fed 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateEmbeddedPersistentEntity.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateEmbeddedPersistentEntity.java @@ -5,11 +5,22 @@ import org.grails.datastore.mapping.model.*; public class HibernateEmbeddedPersistentEntity extends EmbeddedPersistentEntity<Mapping> implements GrailsHibernatePersistentEntity { private final ClassMapping<Mapping> classMapping; + private String dataSourceName; public Mapping getMappedForm() { return classMapping.getMappedForm(); } + @Override + public void setDataSourceName(String dataSourceName) { + this.dataSourceName = dataSourceName; + } + + @Override + public String getDataSourceName() { + return dataSourceName; + } + @Override public GrailsHibernatePersistentProperty getIdentity() { return super.getIdentity() instanceof GrailsHibernatePersistentProperty ghpp ? ghpp : null; diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java index b331e14d25..865fb69135 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContext.java @@ -27,7 +27,6 @@ import org.grails.datastore.mapping.engine.types.CustomTypeMarshaller; import org.grails.datastore.mapping.model.*; import org.grails.datastore.mapping.model.config.GormProperties; import org.grails.datastore.mapping.model.config.JpaMappingConfigurationStrategy; -import org.grails.datastore.mapping.model.types.*; import org.grails.datastore.mapping.reflect.ClassUtils; import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings; import org.grails.orm.hibernate.proxy.HibernateProxyHandler; @@ -193,12 +192,13 @@ public class HibernateMappingContext extends AbstractMappingContext { return super.getPersistentEntity(name); } - public Collection<GrailsHibernatePersistentEntity> getHibernatePersistentEntities() { + public Collection<GrailsHibernatePersistentEntity> getHibernatePersistentEntities(String dataSourceName) { return Optional.ofNullable(persistentEntities) .orElse(new ArrayList<>()) .stream() .filter(GrailsHibernatePersistentEntity.class::isInstance) .map(GrailsHibernatePersistentEntity.class::cast) + .peek(persistentEntity -> persistentEntity.setDataSourceName(dataSourceName)) .toList(); } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernatePersistentEntity.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernatePersistentEntity.java index 7ae4e33475..ca65cfe652 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernatePersistentEntity.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/HibernatePersistentEntity.java @@ -30,6 +30,7 @@ import jakarta.persistence.Entity; */ public class HibernatePersistentEntity extends AbstractPersistentEntity<Mapping> implements GrailsHibernatePersistentEntity { private final AbstractClassMapping<Mapping> classMapping; + private String dataSourceName; public HibernatePersistentEntity(Class javaClass, final MappingContext context) { @@ -38,6 +39,16 @@ public class HibernatePersistentEntity extends AbstractPersistentEntity<Mapping> this.classMapping = new HibernateClassMapping(this, context); } + @Override + public void setDataSourceName(String dataSourceName) { + this.dataSourceName = dataSourceName; + } + + @Override + public String getDataSourceName() { + return dataSourceName; + } + @Override protected boolean includeIdentifiers() { return true; diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java index 24437f3369..84c0ff8d52 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinder.java @@ -108,7 +108,7 @@ public class CollectionSecondPassBinder { } } //NOTE: this will build the set for the in clause if it has sublcasses - java.util.Set<String> discSet = buildDiscriminatorSet(referenced); + java.util.Set<String> discSet = referenced.buildDiscriminatorSet(); String inclause = String.join(",", discSet); collection.setWhere(discriminatorColumnName + " in (" + inclause + ")"); @@ -475,31 +475,4 @@ public class CollectionSecondPassBinder { key.setSorted(collection.isSorted()); return key; } - - private java.util.Set<String> buildDiscriminatorSet(GrailsHibernatePersistentEntity domainClass) { - java.util.Set<String> theSet = new java.util.HashSet<>(); - - Mapping mapping = domainClass.getMappedForm(); - String discriminator = domainClass.getName(); - if (mapping != null && mapping.getDiscriminator() != null) { - DiscriminatorConfig discriminatorConfig = mapping.getDiscriminator(); - if(discriminatorConfig.getValue() != null) { - discriminator = discriminatorConfig.getValue(); - } - } - Mapping rootMapping = domainClass.getHibernateRootEntity().getMappedForm(); - String quote = "'"; - if (rootMapping != null && rootMapping.getDatasources() != null) { - DiscriminatorConfig discriminatorConfig = rootMapping.getDiscriminator(); - if(discriminatorConfig != null && discriminatorConfig.getType() != null && !discriminatorConfig.getType().equals("string")) - quote = ""; - } - theSet.add(quote + discriminator + quote); - - final java.util.Collection<PersistentEntity> childEntities = domainClass.getMappingContext().getDirectChildEntities(domainClass); - for (PersistentEntity subClass : childEntities) { - theSet.addAll(buildDiscriminatorSet((GrailsHibernatePersistentEntity) subClass)); - } - return theSet; - } } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntitySpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntitySpec.groovy new file mode 100644 index 0000000000..1f7421afe2 --- /dev/null +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsHibernatePersistentEntitySpec.groovy @@ -0,0 +1,258 @@ +package org.grails.orm.hibernate.cfg + +import grails.gorm.annotation.Entity +import grails.gorm.specs.HibernateGormDatastoreSpec + +class GrailsHibernatePersistentEntitySpec extends HibernateGormDatastoreSpec { + + void setupSpec() { + manager.addAllDomainClasses([ + Simple, + CustomDiscriminator, + NumericDiscriminator, + Vehicle, + Car, + Truck, + Person, + AddressOwner, + CustomTableEntity, + DerivedPropertyEntity + ]) + } + + void "test buildDiscriminatorSet for simple entity"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(Simple) as GrailsHibernatePersistentEntity + + when: + Set<String> result = entity.buildDiscriminatorSet() + + then: + result == ["'org.grails.orm.hibernate.cfg.Simple'"] as Set + } + + void "test buildDiscriminatorSet with custom discriminator value"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(CustomDiscriminator) as GrailsHibernatePersistentEntity + + when: + Set<String> result = entity.buildDiscriminatorSet() + + then: + result == ["'custom_val'"] as Set + } + + void "test buildDiscriminatorSet with numeric discriminator type"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(NumericDiscriminator) as GrailsHibernatePersistentEntity + + when: + Set<String> result = entity.buildDiscriminatorSet() + + then: + result == ["1"] as Set + } + + void "test buildDiscriminatorSet with hierarchy"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(Vehicle) as GrailsHibernatePersistentEntity + + when: + Set<String> result = entity.buildDiscriminatorSet() + + then: + result == ["'VEHICLE'", "'CAR'", "'TRUCK'"] as Set + } + + void "test getHibernateRootEntity and getRootMapping"() { + given: + GrailsHibernatePersistentEntity vehicle = getPersistentEntity(Vehicle) as GrailsHibernatePersistentEntity + GrailsHibernatePersistentEntity car = getPersistentEntity(Car) as GrailsHibernatePersistentEntity + + expect: + car.hibernateRootEntity == vehicle + car.rootMapping == vehicle.mappedForm + vehicle.hibernateRootEntity == vehicle + vehicle.rootMapping == vehicle.mappedForm + } + + void "test isTablePerHierarchySubclass"() { + given: + GrailsHibernatePersistentEntity vehicle = getPersistentEntity(Vehicle) as GrailsHibernatePersistentEntity + GrailsHibernatePersistentEntity car = getPersistentEntity(Car) as GrailsHibernatePersistentEntity + GrailsHibernatePersistentEntity simple = getPersistentEntity(Simple) as GrailsHibernatePersistentEntity + + expect: + !vehicle.isTablePerHierarchySubclass() + car.isTablePerHierarchySubclass() + !simple.isTablePerHierarchySubclass() + } + + void "test getDiscriminatorValue"() { + given: + GrailsHibernatePersistentEntity vehicle = getPersistentEntity(Vehicle) as GrailsHibernatePersistentEntity + GrailsHibernatePersistentEntity car = getPersistentEntity(Car) as GrailsHibernatePersistentEntity + GrailsHibernatePersistentEntity simple = getPersistentEntity(Simple) as GrailsHibernatePersistentEntity + + expect: + vehicle.discriminatorValue == "VEHICLE" + car.discriminatorValue == "CAR" + simple.discriminatorValue == "org.grails.orm.hibernate.cfg.Simple" + } + + void "test getPersistentPropertiesToBind"() { + given: + GrailsHibernatePersistentEntity person = getPersistentEntity(Person) as GrailsHibernatePersistentEntity + + when: + def props = person.getPersistentPropertiesToBind() + + then: + props.size() == 1 + props[0].name == "name" + } + + void "test getChildEntities"() { + given: + GrailsHibernatePersistentEntity vehicle = getPersistentEntity(Vehicle) as GrailsHibernatePersistentEntity + + when: + def children = vehicle.getChildEntities("DEFAULT") + + then: + children.size() == 2 + children.any { it.name == Car.name } + children.any { it.name == Truck.name } + } + + void "test isComponentPropertyNullable"() { + given: + GrailsHibernatePersistentEntity addressOwner = getPersistentEntity(AddressOwner) as GrailsHibernatePersistentEntity + def addressProp = addressOwner.getPropertyByName("address") + + expect: + addressOwner.isComponentPropertyNullable(addressProp) == false + } + + void "test getMultiTenantFilterCondition"() { + given: + GrailsHibernatePersistentEntity entity = Spy(getPersistentEntity(Person)) as GrailsHibernatePersistentEntity + def tenantIdProp = Mock(org.grails.datastore.mapping.model.types.TenantId) + entity.getTenantId() >> tenantIdProp + def fetcher = Mock(org.grails.orm.hibernate.cfg.domainbinding.DefaultColumnNameFetcher) + fetcher.getDefaultColumnName(tenantIdProp) >> "tenant_id" + + expect: + entity.getMultiTenantFilterCondition(fetcher) == ":tenantId = tenant_id" + } + + void "test getSchema and getCatalog"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(CustomTableEntity) as GrailsHibernatePersistentEntity + def collector = getCollector() + + expect: + entity.getSchema(collector) == "custom_schema" + entity.getCatalog(collector) == "custom_catalog" + } + + void "test configureDerivedProperties"() { + given: + GrailsHibernatePersistentEntity entity = getPersistentEntity(DerivedPropertyEntity) as GrailsHibernatePersistentEntity + def prop = entity.getPropertyByName("fullName") + + when: + entity.configureDerivedProperties() + + then: + prop.mappedForm.derived == true + } + + void "test dataSourceName injection"() { + when: + def entities = getMappingContext().getHibernatePersistentEntities("customDS") + + then: + entities.every { it.dataSourceName == "customDS" } + } +} + +@Entity +class Person { + Long id + String name +} + +@Entity +class AddressOwner { + Long id + EntityAddress address + static embedded = ['address'] +} + +class EntityAddress implements Serializable { + String city +} + +@Entity +class CustomTableEntity { + Long id + static mapping = { + table schema: "custom_schema", catalog: "custom_catalog" + } +} + +@Entity +class DerivedPropertyEntity { + Long id + String firstName + String lastName + String fullName + static mapping = { + fullName formula: "CONCAT(first_name, ' ', last_name)" + } +} + + +@Entity +class Simple { + Long id +} + +@Entity +class CustomDiscriminator { + Long id + static mapping = { + discriminator "custom_val" + } +} + +@Entity +class NumericDiscriminator { + Long id + static mapping = { + discriminator value: "1", type: "integer" + } +} + +@Entity +class Vehicle { + Long id + static mapping = { + discriminator "VEHICLE" + } +} + +@Entity +class Car extends Vehicle { + static mapping = { + discriminator "CAR" + } +} + +@Entity +class Truck extends Vehicle { + static mapping = { + discriminator "TRUCK" + } +}
