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

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

commit 217121b3c413dbddfbe49867cda3dcb9c4109daa
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Thu Mar 5 16:05:27 2026 -0600

    hibernate7: CloseSuppressingInvocationHandler
---
 grails-data-hibernate7/core/COVERAGE.md            | 255 +++++++++++++++++++++
 .../CloseSuppressingInvocationHandler.java         |  79 +++++++
 .../CloseSuppressingInvocationHandlerSpec.groovy   |  93 ++++++++
 3 files changed, 427 insertions(+)

diff --git a/grails-data-hibernate7/core/COVERAGE.md 
b/grails-data-hibernate7/core/COVERAGE.md
new file mode 100644
index 0000000000..b69ba9a97e
--- /dev/null
+++ b/grails-data-hibernate7/core/COVERAGE.md
@@ -0,0 +1,255 @@
+# Hibernate 7 Core Module Test Coverage
+
+| Class | Instruction Coverage |
+| :--- | :--- |
+| 
org.grails.orm.hibernate.GrailsHibernateTemplate.CloseSuppressingInvocationHandler
 | 0% |
+| org.grails.orm.hibernate.HibernateDatastore.new 
DataSourceConnectionSourceFactory() {...} | 0% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi._delete_closure2 | 0% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._get_closure1 | 0% |
+| org.grails.orm.hibernate.SessionFactoryHolder | 0% |
+| org.grails.orm.hibernate.cfg.InstanceProxy | 0% |
+| org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy | 0% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedCollectionProperty
 | 0% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingBuilder.new
 GroovyObject() {...} | 0% |
+| 
org.grails.orm.hibernate.exceptions.CouldNotDetermineHibernateDialectException 
| 0% |
+| org.grails.orm.hibernate.exceptions.GrailsHibernateConfigurationException | 
0% |
+| org.grails.orm.hibernate.exceptions.GrailsHibernateException | 0% |
+| org.grails.orm.hibernate.query.HibernateQueryConstants | 0% |
+| org.grails.orm.hibernate.support.DataSourceFactoryBean | 0% |
+| 
org.grails.orm.hibernate.support.HibernateDatastoreConnectionSourcesRegistrar | 
0% |
+| org.grails.orm.hibernate.support.HibernateDatastoreFactoryBean | 0% |
+| org.grails.orm.hibernate.support.HibernateDialectDetectorFactoryBean | 0% |
+| org.grails.orm.hibernate.support.HibernateDialectDetectorFactoryBean.new 
DialectResolutionInfoSource() {...} | 0% |
+| org.grails.orm.hibernate.support.HibernateDialectDetectorFactoryBean.new 
ServiceRegistryImplementor() {...} | 0% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.GeneratorCreationContextWrapper 
| 16% |
+| org.grails.orm.hibernate.InstanceApiHelper | 17% |
+| org.grails.orm.hibernate.GrailsSessionContext | 26% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPassBinder | 
32% |
+| org.grails.orm.hibernate.cfg.GrailsHibernateUtil | 35% |
+| org.grails.orm.hibernate.cfg.Table | 35% |
+| org.grails.orm.hibernate.cfg.ColumnConfig | 42% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPassBinder | 
43% |
+| org.grails.orm.hibernate.exceptions.GrailsQueryException | 44% |
+| org.grails.orm.hibernate.query.MutationQueryDelegate | 45% |
+| org.grails.orm.hibernate.cfg.Identity | 46% |
+| org.grails.orm.hibernate.HibernateDatastore.new HibernateGormEnhancer() 
{...} | 50% |
+| org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration | 54% |
+| org.grails.orm.hibernate.query.GrailsHibernateQueryUtils | 54% |
+| org.grails.orm.hibernate.query.SelectQueryDelegate | 57% |
+| org.grails.orm.hibernate.HibernateDatastore | 59% |
+| org.grails.orm.hibernate.cfg.SortConfig | 59% |
+| org.grails.orm.hibernate.HibernateEventListeners | 60% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedPersistentEntity
 | 60% |
+| org.grails.orm.hibernate.proxy.HibernateProxyHandler | 61% |
+| org.grails.orm.hibernate.HibernateSession | 62% |
+| org.grails.orm.hibernate.cfg.MappingCacheHolder | 63% |
+| org.grails.orm.hibernate.GrailsHibernateTransactionManager | 65% |
+| grails.orm.HibernateCriteriaBuilder | 67% |
+| org.grails.orm.hibernate.cfg.JoinTable | 67% |
+| org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory | 67% |
+| org.grails.orm.hibernate.GrailsHibernateTemplate | 68% |
+| org.grails.orm.hibernate.access.TraitPropertyAccessStrategy | 69% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsIncrementGenerator | 
70% |
+| org.grails.orm.hibernate.query.HqlQueryDelegate | 71% |
+| org.grails.orm.hibernate.cfg.DiscriminatorConfig | 72% |
+| 
org.grails.orm.hibernate.connections.HibernateConnectionSourceSettingsBuilder | 
72% |
+| org.grails.orm.hibernate.cfg.IdentityEnumType | 74% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SingleTableSubclassBinder 
| 74% |
+| org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsNativeGenerator | 
74% |
+| org.grails.orm.hibernate.support.SoftKey | 75% |
+| org.grails.orm.hibernate.EventListenerIntegrator | 76% |
+| org.grails.orm.hibernate.HibernateDatastore.new HibernateDatastore() {...} | 
78% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.CascadeBehaviorFetcher | 78% 
|
+| org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor | 78% |
+| org.grails.orm.hibernate.cfg.Mapping | 79% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingFactory 
| 79% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty
 | 79% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BasicCollectionElementBinder
 | 80% |
+| org.grails.orm.hibernate.cfg.CompositeIdentity | 81% |
+| org.grails.orm.hibernate.multitenancy.MultiTenantEventListener | 81% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionWithJoinTableBinder
 | 82% |
+| org.grails.orm.hibernate.query.GrailsHibernateQueryUtils.new Comparator() 
{...} | 82% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator | 84% 
|
+| org.grails.orm.hibernate.event.listener.HibernateEventListener | 84% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi | 85% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityMapping | 
85% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SimpleValueBinder | 86% |
+| 
org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings.HibernateSettings
 | 86% |
+| org.grails.orm.hibernate.query.PredicateGenerator | 86% |
+| grails.orm.CriteriaMethodInvoker | 87% |
+| org.grails.orm.hibernate.cfg.CacheConfig | 87% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ManyToOneBinder | 87% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionType | 
87% |
+| org.grails.orm.hibernate.HibernateGormStaticApi | 88% |
+| org.grails.orm.hibernate.HibernateGormValidationApi | 88% |
+| org.grails.orm.hibernate.cfg.IdentityEnumType.BidiEnumMap | 88% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.NamespaceNameExtractor | 88% 
|
+| org.grails.orm.hibernate.query.PagedResultList | 88% |
+| org.grails.orm.hibernate.support.HibernateRuntimeUtils | 88% |
+| org.grails.orm.hibernate.cfg.PropertyConfig | 89% |
+| org.grails.orm.hibernate.cfg.PropertyDefinitionDelegate | 89% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsSequenceStyleGenerator
 | 89% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.UniqueKeyForColumnsCreator | 
89% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ClassBinder | 90% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ClassPropertiesBinder | 
90% |
+| org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsTableGenerator | 
90% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOneProperty 
| 90% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty 
| 90% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher | 
90% |
+| org.grails.orm.hibernate.query.HibernateAssociationQuery | 90% |
+| org.grails.orm.hibernate.query.HibernateQueryExecutor | 90% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyProvider | 91% 
|
+| org.grails.orm.hibernate.support.ClosureEventListener | 91% |
+| org.grails.orm.hibernate.HibernateGormEnhancer | 92% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionBinder | 92% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.RootPersistentClassCommonValuesBinder
 | 92% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsSequenceGeneratorEnum
 | 92% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.GrailsEnumType | 92% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.UniqueNameGenerator | 92% |
+| org.grails.orm.hibernate.compiler.HibernateEntityTransformation | 92% |
+| org.grails.orm.hibernate.dirty.GrailsEntityDirtinessStrategy | 92% |
+| org.grails.orm.hibernate.query.HibernateHqlQuery | 92% |
+| org.grails.orm.hibernate.query.HibernateQuery | 92% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi._delete_closure1 | 93% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ColumnBinder | 93% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation | 
93% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingBuilder 
| 93% |
+| org.grails.orm.hibernate.cfg.NaturalId | 94% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SimpleValueColumnBinder | 
94% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity
 | 94% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyBinder
 | 94% |
+| 
org.grails.orm.hibernate.dirty.GrailsEntityDirtinessStrategy._findDirty_closure1
 | 94% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi._performMerge_closure4 | 
95% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi._performPersist_closure5 | 
95% |
+| org.grails.orm.hibernate.HibernateGormValidationApi._validate_closure1 | 95% 
|
+| org.grails.orm.hibernate.cfg.Identity._getProperties_closure1 | 95% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdentifierToManyToOneBinder
 | 95% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.EnumTypeBinder | 95% |
+| org.grails.orm.hibernate.compiler.HibernateEntityTransformation.new 
GroovyObject() {...} | 95% |
+| org.grails.orm.hibernate.query.HqlQueryContext | 95% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._list_closure7 | 96% |
+| org.grails.orm.hibernate.cfg.HibernateMappingContext | 96% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentBinder | 96% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsPropertyBinder | 96% 
|
+| org.grails.orm.hibernate.cfg.domainbinding.util.NamingStrategyWrapper | 96% |
+| grails.gorm.hibernate.mapping.MappingBuilder.ClosureMappingDefinition | 97% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SimpleIdBinder | 97% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingBuilder._id_closure1
 | 97% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionSecondPassBinder
 | 97% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.LogCascadeMapping | 97% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterBinder | 
97% |
+| 
org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings.HibernateSettings.FlushSettings.FlushMode
 | 97% |
+| org.grails.orm.hibernate.query.HibernateQueryArgument | 97% |
+| org.grails.orm.hibernate.query.JpaFromProvider | 97% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.IndexBinder | 98% |
+| org.grails.orm.hibernate.query.ProjectionPredicate | 98% |
+| grails.orm.CriteriaMethods | 99% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ColumnConfigToColumnBinder 
| 99% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.GrailsDomainBinder | 99% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.OrderByClauseBuilder | 99% |
+| grails.gorm.hibernate.mapping.MappingBuilder | 100% |
+| org.grails.orm.hibernate.HibernateDatastore.new Closure() {...} | 100% |
+| org.grails.orm.hibernate.HibernateDatastore.new HibernateDatastore() {...} | 
100% |
+| org.grails.orm.hibernate.HibernateDatastore.new MappingContext.Listener() 
{...} | 100% |
+| org.grails.orm.hibernate.HibernateGormInstanceApi._attach_closure3 | 100% |
+| 
org.grails.orm.hibernate.HibernateGormInstanceApi._getPersistentValue_closure6 
| 100% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._findAllWhere_closure4 | 
100% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._findWhere_closure5 | 100% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._getAllInternal_closure6 | 
100% |
+| 
org.grails.orm.hibernate.HibernateGormStaticApi._getAllInternal_closure6._closure10
 | 100% |
+| 
org.grails.orm.hibernate.HibernateGormStaticApi._getAllInternal_closure6._closure8
 | 100% |
+| 
org.grails.orm.hibernate.HibernateGormStaticApi._getAllInternal_closure6._closure9
 | 100% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._get_closure2 | 100% |
+| org.grails.orm.hibernate.HibernateGormStaticApi._read_closure3 | 100% |
+| org.grails.orm.hibernate.MetadataIntegrator | 100% |
+| org.grails.orm.hibernate.SchemaTenantDataSource | 100% |
+| org.grails.orm.hibernate.access.TraitPropertyAccessStrategy.new 
PropertyAccess() {...} | 100% |
+| 
org.grails.orm.hibernate.cfg.CompositeIdentity._getHibernateProperties_closure1 
| 100% |
+| 
org.grails.orm.hibernate.cfg.CompositeIdentity._getHibernateProperties_closure2 
| 100% |
+| org.grails.orm.hibernate.cfg.GrailsNamedStrategyContributor | 100% |
+| org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.new 
ClassLoaderServiceImpl() {...} | 100% |
+| org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.new 
SessionFactoryObserver() {...} | 100% |
+| org.grails.orm.hibernate.cfg.Identity._getProperties_closure1._closure2 | 
100% |
+| org.grails.orm.hibernate.cfg.PropertyConfig._getTypeName_closure1 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.CollectionForPropertyConfigBinder
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ComponentUpdater | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdBinder | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.ConfiguredDiscriminatorBinder 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.DefaultDiscriminatorBinder 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.DiscriminatorPropertyBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ForeignKeyOneToOneBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.IdentityBinder | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.JoinedSubClassBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.ManyToOneValuesBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.NaturalIdentifierBinder | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.NumericColumnConstraintsBinder
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.OneToOneBinder | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.PropertyBinder | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.RootBinder | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.binder.StringColumnConstraintsBinder 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SubClassBinder | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.SubclassMappingBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.binder.UnionSubclassBinder | 100% 
|
+| org.grails.orm.hibernate.cfg.domainbinding.binder.VersionBinder | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.BagCollectionType 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.ListCollectionType 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.MapCollectionType 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.collectionType.SetCollectionType 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.collectionType.SortedSetCollectionType
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsIdentityGenerator 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsSequenceGeneratorEnum._fromName_closure1
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.generator.GrailsSequenceWrapper | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsJpaMappingConfigurationStrategy
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateBasicProperty 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateClassMapping | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateCustomEnumProperty
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateCustomProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedClassMapping
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToManyProperty
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToOneProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingBuilder._handlePropertyInternal_closure2
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToManyProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleEnumProperty
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateTenantIdProperty 
| 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalMapElementBinder
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalOneToManyLinker
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyBinder | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyColumnUpdater
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionMultiTenantFilterBinder
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionOrderByBinder | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.DependentKeyValueBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.GrailsSecondPass | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPass | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ManyToManyElementBinder | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPass | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.PrimaryKeyValueCreator 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.secondpass.SetSecondPass | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyInverseValuesBinder
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.BasicValueIdCreator | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.CascadeBehavior | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.ConfigureDerivedPropertiesConsumer
 | 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.CreateKeyForProps | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.ForeignKeyColumnCountCalculator 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.GrailsPropertyResolver | 
100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.MultiTenantFilterDefinitionBinder
 | 100% |
+| 
org.grails.orm.hibernate.cfg.domainbinding.util.OrderByClauseBuilder.SortEntry 
| 100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator | 
100% |
+| org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher | 
100% |
+| org.grails.orm.hibernate.connections.HibernateConnectionSource | 100% |
+| org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings | 
100% |
+| org.grails.orm.hibernate.query.AliasMapEntryFunction | 100% |
+| org.grails.orm.hibernate.query.CriteriaAndAlias | 100% |
+| org.grails.orm.hibernate.query.DetachedAssociationFunction | 100% |
+| org.grails.orm.hibernate.query.GrailsRLikeFunctionContributor | 100% |
+| org.grails.orm.hibernate.query.HibernateQuery.new Closure() {...} | 100% |
+| org.grails.orm.hibernate.query.JpaCriteriaQueryCreator | 100% |
+| org.grails.orm.hibernate.query.PagedResultList.new 
GrailsHibernateTemplate.HibernateCallback() {...} | 100% |
+| org.grails.orm.hibernate.query.RegexDialectPattern | 100% |
+| org.hibernate.proxy.HibernateProxyHelper | 100% |
diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandler.java
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandler.java
new file mode 100644
index 0000000000..b4fa3dc6b3
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandler.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import org.hibernate.Session;
+import org.hibernate.query.Query;
+
+/**
+ * Invocation handler that suppresses close calls on Hibernate Sessions. Also 
prepares returned
+ * Query and Criteria objects.
+ *
+ * @see org.hibernate.Session#close
+ */
+public class CloseSuppressingInvocationHandler implements InvocationHandler {
+
+    protected final Session target;
+    protected final GrailsHibernateTemplate template;
+
+    public CloseSuppressingInvocationHandler(Session target, 
GrailsHibernateTemplate template) {
+        this.target = target;
+        this.template = template;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws 
Exception {
+        // Invocation on Session interface coming in...
+
+        switch (method.getName()) {
+            case "equals" -> {
+                // Only consider equal when proxies are identical.
+                return (proxy == args[0]);
+                // Only consider equal when proxies are identical.
+            }
+            case "hashCode" -> {
+                // Use hashCode of Session proxy.
+                return System.identityHashCode(proxy);
+                // Use hashCode of Session proxy.
+            }
+            case "close" -> {
+                // Handle close method: suppress, not valid.
+                return null;
+            }
+        }
+
+
+            Object retVal = method.invoke(target, args);
+
+            // If return value is a Query or Criteria, apply transaction 
timeout.
+            // Applies to createQuery, getNamedQuery, createCriteria.
+            if (retVal instanceof org.hibernate.query.Query<?> query) {
+                template.prepareQuery(query);
+            }
+            if (retVal instanceof Query<?> query) {
+                template.prepareCriteria(query);
+            }
+
+            return retVal;
+
+    }
+}
diff --git 
a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandlerSpec.groovy
 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandlerSpec.groovy
new file mode 100644
index 0000000000..eea98d9883
--- /dev/null
+++ 
b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/CloseSuppressingInvocationHandlerSpec.groovy
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.grails.orm.hibernate
+
+import org.hibernate.Session
+import org.hibernate.query.Query
+import spock.lang.Specification
+import java.lang.reflect.Method
+
+class CloseSuppressingInvocationHandlerSpec extends Specification {
+
+    def "test close is suppressed"() {
+        given:
+        Session target = Mock(Session)
+        GrailsHibernateTemplate template = Mock(GrailsHibernateTemplate)
+        CloseSuppressingInvocationHandler handler = new 
CloseSuppressingInvocationHandler(target, template)
+        Method closeMethod = Session.class.getMethod("close")
+
+        when:
+        def result = handler.invoke(null, closeMethod, null)
+
+        then:
+        0 * target.close()
+        result == null
+    }
+
+    def "test equals and hashCode"() {
+        given:
+        Session target = Mock(Session)
+        GrailsHibernateTemplate template = Mock(GrailsHibernateTemplate)
+        CloseSuppressingInvocationHandler handler = new 
CloseSuppressingInvocationHandler(target, template)
+        Method equalsMethod = Object.class.getMethod("equals", Object.class)
+        Method hashCodeMethod = Object.class.getMethod("hashCode")
+        def proxy = new Object()
+
+        expect:
+        handler.invoke(proxy, equalsMethod, [proxy] as Object[]) == true
+        handler.invoke(proxy, equalsMethod, [new Object()] as Object[]) == 
false
+        handler.invoke(proxy, hashCodeMethod, null) == 
System.identityHashCode(proxy)
+    }
+
+    def "test query preparation"() {
+        given:
+        Session target = Mock(Session)
+        GrailsHibernateTemplate template = Mock(GrailsHibernateTemplate)
+        CloseSuppressingInvocationHandler handler = new 
CloseSuppressingInvocationHandler(target, template)
+        
+        Query hibernateQuery = Mock(Query)
+        Method createQueryMethod = Session.class.getMethod("createQuery", 
String.class)
+        
+        when:
+        def result = handler.invoke(null, createQueryMethod, ["from Book"] as 
Object[])
+
+        then:
+        1 * target.createQuery("from Book") >> hibernateQuery
+        1 * template.prepareQuery(hibernateQuery)
+        result == hibernateQuery
+    }
+
+    def "test criteria preparation"() {
+        given:
+        Session target = Mock(Session)
+        GrailsHibernateTemplate template = Mock(GrailsHibernateTemplate)
+        CloseSuppressingInvocationHandler handler = new 
CloseSuppressingInvocationHandler(target, template)
+        
+        Query jpaQuery = Mock(Query)
+        Method createQueryMethod = Session.class.getMethod("createQuery", 
String.class, Class.class)
+        
+        when:
+        def result = handler.invoke(null, createQueryMethod, ["from Book", 
Object.class] as Object[])
+
+        then:
+        1 * target.createQuery("from Book", Object.class) >> jpaQuery
+        1 * template.prepareCriteria(jpaQuery)
+        result == jpaQuery
+    }
+}

Reply via email to