You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by bo...@apache.org on 2025/07/10 03:01:57 UTC
(grails-core) 19/22: refactoring and testing Binding of Class
This is an automated email from the ASF dual-hosted git repository.
borinquenkid pushed a commit to branch merge-hibernate6
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 381b749fa926f6c4a7656f9326766c982805f2b5
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Sun Jul 6 09:54:10 2025 -0500
refactoring and testing Binding of Class
---
.../orm/hibernate/cfg/GrailsDomainBinder.java | 82 ++++++++-------------
.../hibernate/cfg/domainbinding/ClassBinder.java | 43 +++++++++++
.../gorm/specs/HibernateGormDatastoreSpec.groovy | 79 ++++++++++++++++++--
.../hibernate/cfg/GrailsDomainBinderSpec.groovy | 74 +------------------
.../cfg/domainbinding/ClassBinderSpec.groovy | 85 ++++++++++++++++++++++
5 files changed, 235 insertions(+), 128 deletions(-)
diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index d8ca9123d3..4e57e4739b 100644
--- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -34,6 +34,7 @@ import org.grails.datastore.mapping.model.types.ToOne;
import org.grails.datastore.mapping.reflect.EntityReflector;
import org.grails.datastore.mapping.reflect.NameUtils;
import org.grails.orm.hibernate.access.TraitPropertyAccessStrategy;
+import org.grails.orm.hibernate.cfg.domainbinding.ClassBinder;
import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.boot.internal.MetadataBuildingContextRootImpl;
@@ -109,7 +110,9 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
-;import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
+import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
+
+;
/**
* Handles the binding Grails domain classes and properties to the Hibernate runtime meta model.
@@ -155,6 +158,7 @@ public class GrailsDomainBinder implements MetadataContributor {
private final String sessionFactoryName;
private final String dataSourceName;
private final HibernateMappingContext hibernateMappingContext;
+ private final ClassBinder classBinding;
private Closure defaultMapping;
private PersistentEntityNamingStrategy namingStrategy;
private MetadataBuildingContext metadataBuildingContext;
@@ -163,21 +167,35 @@ public class GrailsDomainBinder implements MetadataContributor {
return metadataBuildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment();
}
-
-
- public GrailsDomainBinder(
- String dataSourceName,
- String sessionFactoryName,
- HibernateMappingContext hibernateMappingContext) {
+ public GrailsDomainBinder(String dataSourceName
+ , String sessionFactoryName
+ , HibernateMappingContext hibernateMappingContext
+ , ClassBinder classBinding) {
this.sessionFactoryName = sessionFactoryName;
this.dataSourceName = dataSourceName;
this.hibernateMappingContext = hibernateMappingContext;
+ this.classBinding = classBinding;
// pre-build mappings
for (PersistentEntity persistentEntity : hibernateMappingContext.getPersistentEntities()) {
evaluateMapping(persistentEntity);
}
}
+
+
+
+ public GrailsDomainBinder(
+ String dataSourceName,
+ String sessionFactoryName,
+ HibernateMappingContext hibernateMappingContext) {
+ this(dataSourceName
+ , sessionFactoryName
+ , hibernateMappingContext
+ , new ClassBinder()
+ );
+
+ }
+
/**
* The default mapping defined by {@link org.grails.datastore.mapping.config.Settings#SETTING_DEFAULT_MAPPING}
* @param defaultMapping The default mapping
@@ -1379,46 +1397,6 @@ public class GrailsDomainBinder implements MetadataContributor {
// no-op, here for compatibility
}
- /**
- * Binds the specified persistant class to the runtime model based on the
- * properties defined in the domain class
- *
- * @param domainClass The Grails domain class
- * @param persistentClass The persistant class
- * @param mappings Existing mappings
- */
- private void bindClass(PersistentEntity domainClass, PersistentClass persistentClass, InFlightMetadataCollector mappings) {
-
- boolean autoImport = mappings.getMetadataBuildingOptions().getMappingDefaults().isAutoImportEnabled();
- org.grails.datastore.mapping.config.Entity mappedForm = domainClass.getMapping().getMappedForm();
- if (mappedForm instanceof Mapping) {
- autoImport = ((Mapping) mappedForm).isAutoImport();
- }
-
- // set lazy loading for now
- persistentClass.setLazy(true);
- final String entityName = domainClass.getName();
- persistentClass.setEntityName(entityName);
- persistentClass.setJpaEntityName(autoImport ? unqualify(entityName) : entityName);
- persistentClass.setProxyInterfaceName(entityName);
- persistentClass.setClassName(entityName);
-
- // set dynamic insert to false
- persistentClass.setDynamicInsert(false);
- // set dynamic update to false
- persistentClass.setDynamicUpdate(false);
- // set select before update to false
- persistentClass.setSelectBeforeUpdate(false);
-
- // add import to mappings
- String en = persistentClass.getEntityName();
-
- if (autoImport && en.indexOf('.') > 0) {
- String unqualified = unqualify(en);
- mappings.addImport(unqualified, en);
- }
- }
-
/**
* Binds a root class (one with no super classes) to the runtime meta model
* based on the supplied Grails domain class
@@ -1434,7 +1412,7 @@ public class GrailsDomainBinder implements MetadataContributor {
}
RootClass root = new RootClass(this.metadataBuildingContext);
root.setAbstract(entity.isAbstract());
- bindClass(entity, root, mappings);
+ classBinding.bindClass(entity, root, mappings);
bindRootPersistentClassCommonValues(entity, root, mappings, sessionFactoryBeanName);
var children = entity.getMappingContext()
@@ -1604,7 +1582,7 @@ public class GrailsDomainBinder implements MetadataContributor {
private void bindUnionSubclass(HibernatePersistentEntity subClass, UnionSubclass unionSubclass,
InFlightMetadataCollector mappings, String sessionFactoryBeanName) throws MappingException {
- bindClass(subClass, unionSubclass, mappings);
+ classBinding.bindClass(subClass, unionSubclass, mappings);
Mapping subMapping = getMapping(subClass.getJavaClass());
@@ -1650,7 +1628,7 @@ public class GrailsDomainBinder implements MetadataContributor {
*/
private void bindJoinedSubClass(HibernatePersistentEntity sub, JoinedSubclass joinedSubclass,
InFlightMetadataCollector mappings, Mapping gormMapping, String sessionFactoryBeanName) {
- bindClass(sub, joinedSubclass, mappings);
+ classBinding.bindClass(sub, joinedSubclass, mappings);
String schemaName = getSchemaName(mappings);
String catalogName = getCatalogName(mappings);
@@ -1700,7 +1678,7 @@ public class GrailsDomainBinder implements MetadataContributor {
*/
private void bindSubClass(HibernatePersistentEntity sub, Subclass subClass, InFlightMetadataCollector mappings,
String sessionFactoryBeanName) {
- bindClass(sub, subClass, mappings);
+ classBinding.bindClass(sub, subClass, mappings);
if (LOG.isDebugEnabled())
LOG.debug("Mapping subclass: " + subClass.getEntityName() +
@@ -3415,7 +3393,7 @@ public class GrailsDomainBinder implements MetadataContributor {
return GrailsHibernateUtil.unqualify(qualifiedName);
}
- private MetadataBuildingContext getMetadataBuildingContext() {
+ public MetadataBuildingContext getMetadataBuildingContext() {
return metadataBuildingContext;
}
diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinder.java
new file mode 100644
index 0000000000..3629b1d20e
--- /dev/null
+++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinder.java
@@ -0,0 +1,43 @@
+package org.grails.orm.hibernate.cfg.domainbinding;
+
+import org.grails.datastore.mapping.model.PersistentEntity;
+import org.grails.orm.hibernate.cfg.Mapping;
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.mapping.PersistentClass;
+
+import static org.grails.orm.hibernate.cfg.GrailsHibernateUtil.unqualify;
+
+public class ClassBinder {
+
+ /**
+ * Binds the specified persistant class to the runtime model based on the
+ * properties defined in the domain class
+ *
+ * @param persistentEntity The Grails domain class
+ * @param persistentClass The persistant class
+ * @param collector Existing collector
+ */
+ public void bindClass(PersistentEntity persistentEntity, PersistentClass persistentClass, InFlightMetadataCollector collector) {
+ persistentClass.setLazy(true);
+ var entityName = persistentEntity.getName();
+ persistentClass.setEntityName(entityName);
+ persistentClass.setJpaEntityName(entityName);
+ persistentClass.setProxyInterfaceName(entityName);
+ persistentClass.setClassName(entityName);
+ persistentClass.setDynamicInsert(false);
+ persistentClass.setDynamicUpdate(false);
+ persistentClass.setSelectBeforeUpdate(false);
+
+ boolean autoImport;
+ if (persistentEntity.getMapping().getMappedForm() instanceof Mapping mappedForm) {
+ autoImport = mappedForm.isAutoImport();
+ } else {
+ autoImport = collector.getMetadataBuildingOptions().getMappingDefaults().isAutoImportEnabled();
+ }
+ if (autoImport) {
+ String unqualified = unqualify(entityName);
+ persistentClass.setJpaEntityName(unqualified);
+ collector.addImport(unqualified, entityName);
+ }
+ }
+}
diff --git a/grails-data-hibernate6/core/src/test/groovy/grails/gorm/specs/HibernateGormDatastoreSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/grails/gorm/specs/HibernateGormDatastoreSpec.groovy
index 0832bd7334..11b5c31bb1 100644
--- a/grails-data-hibernate6/core/src/test/groovy/grails/gorm/specs/HibernateGormDatastoreSpec.groovy
+++ b/grails-data-hibernate6/core/src/test/groovy/grails/gorm/specs/HibernateGormDatastoreSpec.groovy
@@ -2,11 +2,20 @@ package grails.gorm.specs
import org.apache.grails.data.hibernate6.core.GrailsDataHibernate6TckManager
import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
-import org.grails.datastore.mapping.core.DatastoreUtils
-import org.grails.datastore.mapping.core.Session
-import org.springframework.transaction.support.DefaultTransactionDefinition
-import spock.lang.Shared
-import spock.lang.Specification
+import org.grails.orm.hibernate.cfg.GrailsDomainBinder
+import org.grails.orm.hibernate.cfg.HibernateMappingContext
+import org.grails.orm.hibernate.cfg.HibernatePersistentEntity
+import org.hibernate.boot.MetadataSources
+import org.hibernate.boot.internal.BootstrapContextImpl
+import org.hibernate.boot.internal.InFlightMetadataCollectorImpl
+import org.hibernate.boot.internal.MetadataBuilderImpl
+import org.hibernate.boot.registry.BootstrapServiceRegistry
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder
+import org.hibernate.boot.registry.classloading.spi.ClassLoaderService
+import org.hibernate.boot.spi.MetadataContributor
+import org.hibernate.dialect.H2Dialect
+import org.hibernate.internal.SessionFactoryImpl
+import org.hibernate.service.spi.ServiceRegistryImplementor
/**
* The original GormDataStoreSpec destroyed the setup
@@ -30,4 +39,64 @@ class HibernateGormDatastoreSpec extends GrailsDataTckSpec<GrailsDataHibernate6T
'hibernate.jpa.compliance.cascade': 'true',
]
}
+
+ HibernatePersistentEntity createPersistentEntity(String className
+ , Map<String, Class> fieldProperties
+ , Map<String, String> staticMapping
+
+ ) {
+ def classLoader = new GroovyClassLoader()
+ def classText = """
+ package foo
+ import grails.gorm.annotation.Entity
+ import grails.gorm.hibernate.HibernateEntity
+ @Entity
+ class ${className} implements HibernateEntity<${className}> {
+
+ ${fieldProperties.collect { name, type -> "${type.simpleName} ${name}" }.join('\n ')}
+
+ static mapping = {
+ ${staticMapping.collect { name, value -> "${name} ${value}" }.join('\n ')}
+ }
+ }
+ """
+
+ def clazz = classLoader.parseClass(classText)
+ getMappingContext().addPersistentEntity(clazz) as HibernatePersistentEntity
+ }
+
+ protected InFlightMetadataCollectorImpl getCollector() {
+ def bootstrapServiceRegistry = getServiceRegistry()
+ .getParentServiceRegistry()
+ .getParentServiceRegistry() as BootstrapServiceRegistry
+ def serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
+ .applySetting("hibernate.dialect", H2Dialect.class.getName())
+ .applySetting("jakarta.persistence.jdbc.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1")
+ .applySetting("jakarta.persistence.jdbc.driver", "org.h2.Driver")
+ .build()
+ def options = new MetadataBuilderImpl(
+ new MetadataSources(serviceRegistry)
+ ).getMetadataBuildingOptions()
+ new InFlightMetadataCollectorImpl(
+ new BootstrapContextImpl( serviceRegistry, options)
+ , options);
+ }
+
+ protected HibernateMappingContext getMappingContext() {
+ manager.hibernateDatastore.getMappingContext()
+ }
+
+ protected GrailsDomainBinder getGrailsDomainBinder() {
+ def registry = getServiceRegistry()
+ registry
+ .getParentServiceRegistry()
+ .getService(ClassLoaderService.class)
+ .loadJavaServices(MetadataContributor.class)
+ .find { it instanceof GrailsDomainBinder }
+ }
+
+ protected ServiceRegistryImplementor getServiceRegistry() {
+ (manager.hibernateDatastore.sessionFactory as SessionFactoryImpl)
+ .getServiceRegistry()
+ }
}
diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinderSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinderSpec.groovy
index 6d9c841f62..eb3b349bb6 100644
--- a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinderSpec.groovy
+++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinderSpec.groovy
@@ -1,21 +1,6 @@
package org.grails.orm.hibernate.cfg
import grails.gorm.specs.HibernateGormDatastoreSpec
-import org.apache.grails.data.testing.tck.domains.EagerOwner
-import org.apache.grails.data.testing.tck.domains.Face
-import org.apache.grails.data.testing.tck.domains.Person
-import org.apache.grails.data.testing.tck.domains.Pet
-import org.hibernate.boot.MetadataSources
-import org.hibernate.boot.internal.BootstrapContextImpl
-import org.hibernate.boot.internal.InFlightMetadataCollectorImpl
-import org.hibernate.boot.internal.MetadataBuilderImpl
-import org.hibernate.boot.registry.BootstrapServiceRegistry
-import org.hibernate.boot.registry.StandardServiceRegistryBuilder
-import org.hibernate.boot.registry.classloading.spi.ClassLoaderService
-import org.hibernate.internal.SessionFactoryImpl
-import org.hibernate.service.spi.ServiceRegistryImplementor
-import org.hibernate.dialect.H2Dialect
-import org.hibernate.boot.spi.MetadataContributor
class GrailsDomainBinderSpec extends HibernateGormDatastoreSpec {
@@ -25,67 +10,14 @@ class GrailsDomainBinderSpec extends HibernateGormDatastoreSpec {
def collector = getCollector()
def grailsDomainBinder = getGrailsDomainBinder()
-
- def args = ["Book", [title: String, author: String, publishedYear: Integer]]
- def persistentEntity = createPersistentEntity(args[0] as String, args[1] as Map<String, Class>)
+ def simpleName = "Book"
+ def fieldProperties = [title: String]
+ def persistentEntity = createPersistentEntity(simpleName, fieldProperties, [:])
grailsDomainBinder.bindRoot(persistentEntity, collector,"sessionFactoryName")
println("when")
then:
1 == 1
}
- HibernatePersistentEntity createPersistentEntity(String className, Map<String, Class> properties) {
- def classLoader = new GroovyClassLoader()
- def classText = """
- import grails.gorm.annotation.Entity
- import grails.gorm.hibernate.HibernateEntity
- @Entity
- class ${className} implements HibernateEntity<${className}> {
- ${properties.collect { name, type -> "${type.simpleName} ${name}" }.join('\n ')}
-
- static mapping = {
- id generator: 'native'
- version false
- }
- }
- """
-
- def clazz = classLoader.parseClass(classText)
- getMappingContext().addPersistentEntity(clazz) as HibernatePersistentEntity
- }
-
- private InFlightMetadataCollectorImpl getCollector() {
- def bootstrapServiceRegistry = getServiceRegistry()
- .getParentServiceRegistry()
- .getParentServiceRegistry() as BootstrapServiceRegistry
- def serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
- .applySetting("hibernate.dialect", H2Dialect.class.getName())
- .applySetting("jakarta.persistence.jdbc.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1")
- .applySetting("jakarta.persistence.jdbc.driver", "org.h2.Driver")
- .build()
- def options = new MetadataBuilderImpl(
- new MetadataSources(serviceRegistry)
- ).getMetadataBuildingOptions()
- new InFlightMetadataCollectorImpl(
- new BootstrapContextImpl( serviceRegistry, options)
- , options);
- }
- private HibernateMappingContext getMappingContext() {
- manager.hibernateDatastore.getMappingContext()
- }
-
- private GrailsDomainBinder getGrailsDomainBinder() {
- def registry = getServiceRegistry()
- registry
- .getParentServiceRegistry()
- .getService(ClassLoaderService.class)
- .loadJavaServices(MetadataContributor.class)
- .find { it instanceof GrailsDomainBinder }
- }
-
- private ServiceRegistryImplementor getServiceRegistry() {
- (manager.hibernateDatastore.sessionFactory as SessionFactoryImpl)
- .getServiceRegistry()
- }
}
\ No newline at end of file
diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinderSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinderSpec.groovy
new file mode 100644
index 0000000000..478a048d13
--- /dev/null
+++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/ClassBinderSpec.groovy
@@ -0,0 +1,85 @@
+package org.grails.orm.hibernate.cfg.domainbinding
+
+import grails.gorm.specs.HibernateGormDatastoreSpec
+import org.hibernate.mapping.RootClass
+
+class ClassBinderSpec extends HibernateGormDatastoreSpec {
+
+
+ void "Test defaults"() {
+ when:
+
+ def collector = getCollector()
+ def grailsDomainBinder = getGrailsDomainBinder()
+
+ def simpleName = "Book"
+ def persistentName = "foo.Book"
+ def persistentEntity = createPersistentEntity(simpleName, [:], [:])
+ def root = new RootClass(grailsDomainBinder.metadataBuildingContext);
+ def binder = new ClassBinder()
+
+ binder.bindClass(persistentEntity,root, collector)
+ then:
+ root.getEntityName() == persistentName
+ root.getJpaEntityName() == simpleName
+ root.getProxyInterfaceName() == persistentName
+ root.getClassName() == persistentName
+ root.isLazy()
+ !root.useDynamicInsert()
+ !root.useDynamicUpdate()
+ !root.hasSelectBeforeUpdate()
+ collector.getImports()[simpleName] == persistentName
+ }
+
+ void "Test autoImport true"() {
+ when:
+
+ def collector = getCollector()
+ def grailsDomainBinder = getGrailsDomainBinder()
+
+ def simpleName = "Book"
+ def persistentName = "foo.Book"
+ def persistentEntity = createPersistentEntity(simpleName, [:], [autoImport: "true"])
+ def root = new RootClass(grailsDomainBinder.metadataBuildingContext);
+ def binder = new ClassBinder()
+
+ binder.bindClass(persistentEntity,root, collector)
+ then:
+ root.getEntityName() == persistentName
+ root.getJpaEntityName() == simpleName
+ root.getProxyInterfaceName() == persistentName
+ root.getClassName() == persistentName
+ root.isLazy()
+ !root.useDynamicInsert()
+ !root.useDynamicUpdate()
+ !root.hasSelectBeforeUpdate()
+ collector.getImports()[simpleName] == persistentName
+ }
+
+ void "Test autoImport false"() {
+ when:
+
+ def collector = getCollector()
+ def grailsDomainBinder = getGrailsDomainBinder()
+
+ def simpleName = "Book"
+ def persistentName = "foo.Book"
+ def persistentEntity = createPersistentEntity(simpleName, [:], [autoImport: "false"])
+ def root = new RootClass(grailsDomainBinder.metadataBuildingContext);
+ def binder = new ClassBinder()
+
+ binder.bindClass(persistentEntity,root, collector)
+ then:
+ root.getEntityName() == persistentName
+ root.getJpaEntityName() == persistentName
+ root.getProxyInterfaceName() == persistentName
+ root.getClassName() == persistentName
+ root.isLazy()
+ !root.useDynamicInsert()
+ !root.useDynamicUpdate()
+ !root.hasSelectBeforeUpdate()
+ !collector.getImports()[simpleName]
+ }
+
+
+}