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 2026/02/23 20:33:41 UTC
(grails-core) 01/11: refactor HibernateMappingFactory to standalone class
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 668a0af1c199aaa9f053e692b86e80ce33b0e67a
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Sat Feb 21 22:33:38 2026 -0600
refactor HibernateMappingFactory to standalone class
---
.../orm/hibernate/cfg/HibernateMappingContext.java | 261 ++-------------------
.../hibernate/HibernateMappingFactory.java | 200 ++++++++++++++++
.../gorm/specs/HibernateMappingFactorySpec.groovy | 236 +++++++++++++++++++
.../cfg/HibernateMappingContextSpec.groovy | 4 +-
4 files changed, 454 insertions(+), 247 deletions(-)
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 e8d86775e8..f23f9d443b 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
@@ -1,61 +1,32 @@
/*
- * 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
+ * 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
+ * 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.
+ * 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.cfg;
import grails.gorm.hibernate.HibernateEntity;
import groovy.lang.Closure;
-
-import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.grails.datastore.gorm.GormEntity;
-import org.grails.datastore.mapping.config.AbstractGormMappingFactory;
-import org.grails.datastore.mapping.config.Property;
-import org.grails.datastore.mapping.config.groovy.MappingConfigurationBuilder;
-import org.grails.datastore.mapping.engine.types.CustomTypeMarshaller;
import org.grails.datastore.mapping.model.*;
-import org.grails.datastore.mapping.reflect.ClassUtils;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsJpaMappingConfigurationStrategy;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateBasicProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateCustomProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedCollectionProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedPersistentEntity;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentity;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityMapping;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateIdentityProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToManyProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateManyToOneProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingBuilder;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToManyProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateOneToOneProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateSimpleProperty;
-import org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateTenantIdProperty;
+import org.grails.orm.hibernate.cfg.domainbinding.hibernate.*;
import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings;
import org.grails.orm.hibernate.proxy.HibernateProxyHandler;
/**
- * A Mapping context for Hibernate
+ * A Mapping context for Hibernate optimized for Java to Groovy conversion.
*
* @author Graeme Rocher
* @since 5.0
@@ -65,22 +36,9 @@ public class HibernateMappingContext extends AbstractMappingContext {
private final HibernateMappingFactory mappingFactory;
private final MappingConfigurationStrategy syntaxStrategy;
- /**
- * Construct a HibernateMappingContext for the given arguments
- *
- * @param settings The {@link HibernateConnectionSourceSettings} settings
- * @param contextObject The context object (for example a Spring ApplicationContext)
- * @param persistentClasses The persistent classes
- */
- public HibernateMappingContext(
- HibernateConnectionSourceSettings settings,
- Object contextObject,
- Class... persistentClasses) {
+ public HibernateMappingContext(HibernateConnectionSourceSettings settings, Object contextObject, Class... persistentClasses) {
this.mappingFactory = new HibernateMappingFactory();
-
- // The mapping factory needs to be configured before initialize can be safely called
initialize(settings);
-
if (settings != null) {
this.mappingFactory.setDefaultMapping(settings.getDefault().getMapping());
this.mappingFactory.setDefaultConstraints(settings.getDefault().getConstraints());
@@ -91,8 +49,7 @@ public class HibernateMappingContext extends AbstractMappingContext {
addPersistentEntities(persistentClasses);
}
- public HibernateMappingContext(
- HibernateConnectionSourceSettings settings, Class... persistentClasses) {
+ public HibernateMappingContext(HibernateConnectionSourceSettings settings, Class... persistentClasses) {
this(settings, null, persistentClasses);
}
@@ -100,11 +57,6 @@ public class HibernateMappingContext extends AbstractMappingContext {
this(new HibernateConnectionSourceSettings());
}
- /**
- * Sets the default constraints to be used
- *
- * @param defaultConstraints The default constraints
- */
public void setDefaultConstraints(Closure defaultConstraints) {
this.mappingFactory.setDefaultConstraints(defaultConstraints);
}
@@ -132,8 +84,7 @@ public class HibernateMappingContext extends AbstractMappingContext {
@Override
protected boolean isValidMappingStrategy(Class javaClass, Object mappingStrategy) {
- return HibernateEntity.class.isAssignableFrom(javaClass)
- || super.isValidMappingStrategy(javaClass, mappingStrategy);
+ return HibernateEntity.class.isAssignableFrom(javaClass) || super.isValidMappingStrategy(javaClass, mappingStrategy);
}
@Override
@@ -157,8 +108,7 @@ public class HibernateMappingContext extends AbstractMappingContext {
return super.getPersistentEntity(name);
}
- public Collection<GrailsHibernatePersistentEntity> getHibernatePersistentEntities(
- String dataSourceName) {
+ public Collection<GrailsHibernatePersistentEntity> getHibernatePersistentEntities(String dataSourceName) {
List<GrailsHibernatePersistentEntity> result = new ArrayList<>();
if (persistentEntities != null) {
for (PersistentEntity entity : persistentEntities) {
@@ -170,183 +120,4 @@ public class HibernateMappingContext extends AbstractMappingContext {
}
return result;
}
-
- class HibernateMappingFactory extends AbstractGormMappingFactory<Mapping, PropertyConfig> {
-
- public HibernateMappingFactory() {}
-
- @Override
- protected MappingConfigurationBuilder createConfigurationBuilder(
- PersistentEntity entity, Mapping mapping) {
- return new HibernateMappingBuilder(mapping, entity.getName(), defaultConstraints);
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.Identity<PropertyConfig> createIdentity(
- PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
- HibernateIdentityProperty identity = new HibernateIdentityProperty(owner, context, pd);
- PropertyMapping<PropertyConfig> propertyMapping = createPropertyMapping(identity, owner);
- identity.setMapping(propertyMapping);
- return identity;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.TenantId<PropertyConfig> createTenantId(
- PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
- HibernateTenantIdProperty tenantId = new HibernateTenantIdProperty(owner, context, pd);
- tenantId.setMapping(createDerivedPropertyMapping(tenantId, owner));
- return tenantId;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.Custom<PropertyConfig> createCustom(
- PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
- final Class<?> propertyType = pd.getPropertyType();
- CustomTypeMarshaller customTypeMarshaller = findCustomType(context, propertyType);
- if (customTypeMarshaller == null && propertyType.isEnum()) {
- customTypeMarshaller = findCustomType(context, Enum.class);
- }
- HibernateCustomProperty custom =
- new HibernateCustomProperty(owner, context, pd, customTypeMarshaller);
- custom.setMapping(createPropertyMapping(custom, owner));
- return custom;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.Simple<PropertyConfig> createSimple(
- PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
- HibernateSimpleProperty simple = new HibernateSimpleProperty(owner, context, pd);
- simple.setMapping(createPropertyMapping(simple, owner));
- return simple;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.ToOne createOneToOne(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateOneToOneProperty oneToOne = new HibernateOneToOneProperty(entity, context, property);
- oneToOne.setMapping(createPropertyMapping(oneToOne, entity));
- return oneToOne;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.ToOne createManyToOne(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateManyToOneProperty manyToOne =
- new HibernateManyToOneProperty(entity, context, property);
- manyToOne.setMapping(createPropertyMapping(manyToOne, entity));
- return manyToOne;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.OneToMany createOneToMany(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateOneToManyProperty oneToMany =
- new HibernateOneToManyProperty(entity, context, property);
- oneToMany.setMapping(createPropertyMapping(oneToMany, entity));
- return oneToMany;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.ManyToMany createManyToMany(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateManyToManyProperty manyToMany =
- new HibernateManyToManyProperty(entity, context, property);
- manyToMany.setMapping(createPropertyMapping(manyToMany, entity));
- return manyToMany;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.Embedded createEmbedded(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateEmbeddedProperty embedded = new HibernateEmbeddedProperty(entity, context, property);
- embedded.setMapping(createPropertyMapping(embedded, entity));
- return embedded;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.EmbeddedCollection createEmbeddedCollection(
- PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
- HibernateEmbeddedCollectionProperty embedded =
- new HibernateEmbeddedCollectionProperty(entity, context, property);
- embedded.setMapping(createPropertyMapping(embedded, entity));
- return embedded;
- }
-
- @Override
- public org.grails.datastore.mapping.model.types.Basic createBasicCollection(
- PersistentEntity entity,
- MappingContext context,
- PropertyDescriptor property,
- Class collectionType) {
- HibernateBasicProperty basic =
- new HibernateBasicProperty((GrailsHibernatePersistentEntity) entity, context, property);
- basic.setMapping(createPropertyMapping(basic, entity));
-
- CustomTypeMarshaller customTypeMarshaller =
- findCustomType(context, property.getPropertyType());
- if (collectionType != null && collectionType.isEnum()) {
- customTypeMarshaller = findCustomType(context, collectionType);
- if (customTypeMarshaller == null) {
- customTypeMarshaller = findCustomType(context, Enum.class);
- }
- }
-
- if (customTypeMarshaller != null) {
- basic.setCustomTypeMarshaller(customTypeMarshaller);
- }
-
- return basic;
- }
-
- @Override
- public IdentityMapping createIdentityMapping(final ClassMapping classMapping) {
- final Mapping mappedForm = (Mapping) createMappedForm(classMapping.getEntity());
- final HibernateIdentity identity = mappedForm.getIdentity();
- final ValueGenerator generator;
- if (identity instanceof Identity) {
- Identity id = (Identity) identity;
- String generatorName = id.getGenerator();
- if (generatorName != null) {
- ValueGenerator resolvedGenerator;
- try {
- resolvedGenerator =
- ValueGenerator.valueOf(generatorName.toUpperCase(java.util.Locale.ENGLISH));
- } catch (IllegalArgumentException e) {
- if (generatorName.equalsIgnoreCase("table")) {
- resolvedGenerator = ValueGenerator.CUSTOM;
- } else if (ClassUtils.isPresent(generatorName)) {
- resolvedGenerator = ValueGenerator.CUSTOM;
- } else {
- throw new DatastoreConfigurationException(
- "Invalid id generation strategy for entity ["
- + classMapping.getEntity().getName()
- + "]: "
- + generatorName);
- }
- }
- generator = resolvedGenerator;
- } else {
- generator = ValueGenerator.AUTO;
- }
- } else {
- generator = ValueGenerator.AUTO;
- }
- return new HibernateIdentityMapping(identity, generator, classMapping);
- }
-
- @Override
- protected boolean allowArbitraryCustomTypes() {
- return true;
- }
-
- @Override
- protected Class<PropertyConfig> getPropertyMappedFormType() {
- return PropertyConfig.class;
- }
-
- @Override
- protected Class<Mapping> getEntityMappedFormType() {
- return Mapping.class;
- }
- }
-}
+}
\ No newline at end of file
diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.java
new file mode 100644
index 0000000000..7df263a4ef
--- /dev/null
+++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingFactory.java
@@ -0,0 +1,200 @@
+/*
+ * 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.cfg.domainbinding.hibernate;
+
+import java.beans.PropertyDescriptor;
+import java.util.Locale;
+
+import org.grails.datastore.mapping.config.AbstractGormMappingFactory;
+import org.grails.datastore.mapping.config.groovy.MappingConfigurationBuilder;
+import org.grails.datastore.mapping.engine.types.CustomTypeMarshaller;
+import org.grails.datastore.mapping.model.*;
+import org.grails.datastore.mapping.model.types.*;
+import org.grails.datastore.mapping.reflect.ClassUtils;
+import org.grails.orm.hibernate.cfg.Identity;
+import org.grails.orm.hibernate.cfg.Mapping;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+
+/**
+ * The {@link AbstractGormMappingFactory} implementation for Hibernate, responsible for
+ * creating all Hibernate-specific persistent property and identity mapping instances.
+ */
+public class HibernateMappingFactory extends AbstractGormMappingFactory<Mapping, PropertyConfig> {
+
+ public HibernateMappingFactory() {
+ }
+
+ @Override
+ protected MappingConfigurationBuilder createConfigurationBuilder(PersistentEntity entity, Mapping mapping) {
+ return new HibernateMappingBuilder(mapping, entity.getName(), defaultConstraints);
+ }
+
+ @Override
+ public org.grails.datastore.mapping.model.types.Identity<PropertyConfig> createIdentity(
+ PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
+ HibernateIdentityProperty identity = new HibernateIdentityProperty(owner, context, pd);
+ identity.setMapping(createPropertyMapping(identity, owner));
+ return identity;
+ }
+
+ @Override
+ public TenantId<PropertyConfig> createTenantId(
+ PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
+ HibernateTenantIdProperty tenantId = new HibernateTenantIdProperty(owner, context, pd);
+ tenantId.setMapping(createDerivedPropertyMapping(tenantId, owner));
+ return tenantId;
+ }
+
+ @Override
+ public Custom<PropertyConfig> createCustom(
+ PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
+ final Class<?> propertyType = pd.getPropertyType();
+ CustomTypeMarshaller customTypeMarshaller = findCustomType(context, propertyType);
+ if (customTypeMarshaller == null && propertyType.isEnum()) {
+ customTypeMarshaller = findCustomType(context, Enum.class);
+ }
+ HibernateCustomProperty custom = new HibernateCustomProperty(owner, context, pd, customTypeMarshaller);
+ custom.setMapping(createPropertyMapping(custom, owner));
+ return custom;
+ }
+
+ @Override
+ public Simple<PropertyConfig> createSimple(
+ PersistentEntity owner, MappingContext context, PropertyDescriptor pd) {
+ HibernateSimpleProperty simple = new HibernateSimpleProperty(owner, context, pd);
+ simple.setMapping(createPropertyMapping(simple, owner));
+ return simple;
+ }
+
+ @Override
+ public ToOne createOneToOne(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateOneToOneProperty oneToOne = new HibernateOneToOneProperty(entity, context, property);
+ oneToOne.setMapping(createPropertyMapping(oneToOne, entity));
+ return oneToOne;
+ }
+
+ @Override
+ public ToOne createManyToOne(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateManyToOneProperty manyToOne = new HibernateManyToOneProperty(entity, context, property);
+ manyToOne.setMapping(createPropertyMapping(manyToOne, entity));
+ return manyToOne;
+ }
+
+ @Override
+ public OneToMany createOneToMany(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateOneToManyProperty oneToMany = new HibernateOneToManyProperty(entity, context, property);
+ oneToMany.setMapping(createPropertyMapping(oneToMany, entity));
+ return oneToMany;
+ }
+
+ @Override
+ public ManyToMany createManyToMany(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateManyToManyProperty manyToMany = new HibernateManyToManyProperty(entity, context, property);
+ manyToMany.setMapping(createPropertyMapping(manyToMany, entity));
+ return manyToMany;
+ }
+
+ @Override
+ public Embedded createEmbedded(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateEmbeddedProperty embedded = new HibernateEmbeddedProperty(entity, context, property);
+ embedded.setMapping(createPropertyMapping(embedded, entity));
+ return embedded;
+ }
+
+ @Override
+ public EmbeddedCollection createEmbeddedCollection(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property) {
+ HibernateEmbeddedCollectionProperty embedded =
+ new HibernateEmbeddedCollectionProperty(entity, context, property);
+ embedded.setMapping(createPropertyMapping(embedded, entity));
+ return embedded;
+ }
+
+ @Override
+ public Basic createBasicCollection(
+ PersistentEntity entity, MappingContext context, PropertyDescriptor property, Class collectionType) {
+ if (entity instanceof GrailsHibernatePersistentEntity ghpEntity) {
+ HibernateBasicProperty basic = new HibernateBasicProperty(ghpEntity, context, property);
+ basic.setMapping(createPropertyMapping(basic, entity));
+ CustomTypeMarshaller customTypeMarshaller = findCustomType(context, property.getPropertyType());
+ if (collectionType != null && collectionType.isEnum()) {
+ customTypeMarshaller = findCustomType(context, collectionType);
+ if (customTypeMarshaller == null) {
+ customTypeMarshaller = findCustomType(context, Enum.class);
+ }
+ }
+ if (customTypeMarshaller != null) {
+ basic.setCustomTypeMarshaller(customTypeMarshaller);
+ }
+ return basic;
+ }
+ return null;
+ }
+
+ @Override
+ public IdentityMapping createIdentityMapping(final ClassMapping classMapping) {
+ final Mapping mappedForm = (Mapping) createMappedForm(classMapping.getEntity());
+ final HibernateIdentity identity = mappedForm.getIdentity();
+ final ValueGenerator generator;
+
+ if (identity instanceof Identity id) {
+ String generatorName = id.getGenerator();
+ if (generatorName != null) {
+ ValueGenerator resolvedGenerator;
+ try {
+ resolvedGenerator = ValueGenerator.valueOf(generatorName.toUpperCase(Locale.ENGLISH));
+ } catch (IllegalArgumentException e) {
+ if (generatorName.equalsIgnoreCase("table") || ClassUtils.isPresent(generatorName)) {
+ resolvedGenerator = ValueGenerator.CUSTOM;
+ } else {
+ throw new DatastoreConfigurationException(
+ String.format("Invalid id generation strategy for entity [%s]: %s",
+ classMapping.getEntity().getName(), generatorName));
+ }
+ }
+ generator = resolvedGenerator;
+ } else {
+ generator = ValueGenerator.AUTO;
+ }
+ } else {
+ generator = ValueGenerator.AUTO;
+ }
+ return new HibernateIdentityMapping(identity, generator, classMapping);
+ }
+
+ @Override
+ protected boolean allowArbitraryCustomTypes() {
+ return true;
+ }
+
+ @Override
+ protected Class<PropertyConfig> getPropertyMappedFormType() {
+ return PropertyConfig.class;
+ }
+
+ @Override
+ protected Class<Mapping> getEntityMappedFormType() {
+ return Mapping.class;
+ }
+}
diff --git a/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
new file mode 100644
index 0000000000..66863795a0
--- /dev/null
+++ b/grails-data-hibernate7/core/src/test/groovy/grails/gorm/specs/HibernateMappingFactorySpec.groovy
@@ -0,0 +1,236 @@
+/*
+ * 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 grails.gorm.specs
+
+import grails.gorm.annotation.Entity
+import grails.gorm.hibernate.HibernateEntity
+import grails.gorm.transactions.Rollback
+import org.grails.datastore.mapping.engine.types.AbstractMappingAwareCustomTypeMarshaller
+import org.grails.datastore.mapping.model.MappingContext
+import org.grails.datastore.mapping.model.PersistentEntity
+import org.grails.datastore.mapping.model.PersistentProperty
+import org.grails.datastore.mapping.model.ValueGenerator
+import org.grails.datastore.mapping.model.types.*
+import org.grails.orm.hibernate.cfg.HibernateMappingContext
+import org.grails.orm.hibernate.cfg.domainbinding.hibernate.*
+import org.grails.orm.hibernate.connections.HibernateConnectionSourceSettings
+
+/**
+ * Spec for {@link HibernateMappingFactory}, verifying that it creates
+ * the correct Hibernate-specific property and identity mapping instances.
+ */
+class HibernateMappingFactorySpec extends HibernateGormDatastoreSpec {
+
+ def setupSpec() {
+ manager.addAllDomainClasses([MappingFactoryBook, MappingFactoryAuthor, MappingFactoryTag,
+ MappingFactoryArticle])
+ }
+
+ // --- unit-style tests (standalone factory) ---
+
+ void "factory can be instantiated standalone"() {
+ when:
+ def factory = new HibernateMappingFactory()
+
+ then:
+ factory != null
+ factory.getPropertyMappedFormType() == org.grails.orm.hibernate.cfg.PropertyConfig
+ factory.getEntityMappedFormType() == org.grails.orm.hibernate.cfg.Mapping
+ }
+
+ void "allowArbitraryCustomTypes returns true"() {
+ expect:
+ new HibernateMappingFactory().allowArbitraryCustomTypes()
+ }
+
+ void "custom type marshaller is registered and detectable"() {
+ given:
+ HibernateConnectionSourceSettings settings = new HibernateConnectionSourceSettings()
+ settings.custom.types = [new FactoryTypeMarshaller(FactoryCustomType)]
+ def ctx = new HibernateMappingContext(settings)
+
+ expect:
+ ctx.mappingFactory.isCustomType(FactoryCustomType)
+ }
+
+ void "custom type marshaller is NOT registered for unrelated type"() {
+ given:
+ HibernateConnectionSourceSettings settings = new HibernateConnectionSourceSettings()
+ settings.custom.types = [new FactoryTypeMarshaller(FactoryCustomType)]
+ def ctx = new HibernateMappingContext(settings)
+
+ expect:
+ !ctx.mappingFactory.isCustomType(String)
+ }
+
+ // --- integration-style tests using live datastore ---
+
+ void "mappingFactory is a HibernateMappingFactory"() {
+ expect:
+ mappingContext.mappingFactory instanceof HibernateMappingFactory
+ }
+
+ void "createSimple produces HibernateSimpleProperty for a String field"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+ def titleProp = entity.persistentProperties.find { it.name == 'title' }
+
+ then:
+ titleProp instanceof HibernateSimpleProperty
+ }
+
+ void "createManyToOne produces HibernateManyToOneProperty for a many-to-one association"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+ def authorProp = entity.persistentProperties.find { it.name == 'author' }
+
+ then:
+ authorProp instanceof HibernateManyToOneProperty
+ }
+
+ void "createOneToMany produces HibernateOneToManyProperty for a one-to-many association"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryAuthor.name)
+ def booksProp = entity.persistentProperties.find { it.name == 'books' }
+
+ then:
+ booksProp instanceof HibernateOneToManyProperty
+ }
+
+ void "createManyToMany produces HibernateManyToManyProperty"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+ def tagsProp = entity.persistentProperties.find { it.name == 'tags' }
+
+ then:
+ tagsProp instanceof HibernateManyToManyProperty
+ }
+
+ void "createIdentity produces HibernateIdentityProperty"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+
+ then:
+ entity.identity instanceof HibernateIdentityProperty
+ }
+
+ void "createIdentityMapping resolves NATIVE generator by default"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+
+ then:
+ entity.mapping.identifier.generator == ValueGenerator.NATIVE
+ }
+
+ void "createIdentityMapping resolves CUSTOM generator for a custom class name"() {
+ when:
+ def ctx = new HibernateMappingContext()
+ PersistentEntity entity = ctx.addPersistentEntity(MappingFactoryCustomIdEntity)
+
+ then:
+ entity.mapping.identifier.generator == ValueGenerator.CUSTOM
+ }
+
+ void "createIdentityMapping returns HibernateIdentityMapping instance"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryBook.name)
+ def idMapping = entity.mapping.identifier
+
+ then:
+ idMapping instanceof HibernateIdentityMapping
+ idMapping.identifierName != null
+ idMapping.identifierName.length > 0
+ }
+
+ void "createEmbedded produces HibernateEmbeddedProperty"() {
+ when:
+ PersistentEntity entity = mappingContext.getPersistentEntity(MappingFactoryArticle.name)
+ def addrProp = entity.persistentProperties.find { it.name == 'metadata' }
+
+ then:
+ addrProp instanceof HibernateEmbeddedProperty
+ }
+
+ @Rollback
+ void "factory-created entities can be persisted and retrieved"() {
+ when:
+ def author = new MappingFactoryAuthor(name: 'Test Author').save(flush: true)
+ def book = new MappingFactoryBook(title: 'Test Book', author: author).save(flush: true)
+
+ then:
+ MappingFactoryBook.count() >= 1
+ MappingFactoryBook.findByTitle('Test Book')?.author?.name == 'Test Author'
+ }
+}
+
+// --- domain classes ---
+
+@Entity
+class MappingFactoryAuthor implements HibernateEntity<MappingFactoryAuthor> {
+ String name
+ static hasMany = [books: MappingFactoryBook]
+}
+
+@Entity
+class MappingFactoryBook implements HibernateEntity<MappingFactoryBook> {
+ String title
+ MappingFactoryAuthor author
+ static belongsTo = [author: MappingFactoryAuthor]
+ static hasMany = [tags: MappingFactoryTag]
+}
+
+@Entity
+class MappingFactoryTag implements HibernateEntity<MappingFactoryTag> {
+ String name
+ static hasMany = [books: MappingFactoryBook]
+ static belongsTo = MappingFactoryBook
+}
+
+@Entity
+class MappingFactoryArticle implements HibernateEntity<MappingFactoryArticle> {
+ String title
+ MappingFactoryMetadata metadata
+ static embedded = ['metadata']
+}
+
+class MappingFactoryMetadata {
+ String description
+}
+
+@Entity
+class MappingFactoryCustomIdEntity implements HibernateEntity<MappingFactoryCustomIdEntity> {
+ String name
+ static mapping = {
+ id generator: 'grails.gorm.specs.FactoryCustomType', type: 'uuid-binary'
+ }
+}
+
+// --- helpers ---
+
+class FactoryCustomType {}
+
+class FactoryTypeMarshaller extends AbstractMappingAwareCustomTypeMarshaller {
+ FactoryTypeMarshaller(Class targetType) { super(targetType) }
+
+ @Override
+ protected Object writeInternal(PersistentProperty property, String key, Object value, Object nativeTarget) { value }
+
+ @Override
+ protected Object readInternal(PersistentProperty property, String key, Object nativeSource) { nativeSource }
+}
diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextSpec.groovy
index d5f78349f5..a102789dd1 100644
--- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextSpec.groovy
+++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/HibernateMappingContextSpec.groovy
@@ -161,10 +161,10 @@ class HibernateMappingContextSpec extends HibernateGormDatastoreSpec {
entity.persistentProperties.find { it.name == "books" } != null
}
- void "getMappingFactory returns the HibernateMappingFactory"() {
+ void "getMappingFactory returns a HibernateMappingFactory"() {
expect:
mappingContext.mappingFactory != null
- mappingContext.mappingFactory.class.simpleName == "HibernateMappingFactory"
+ mappingContext.mappingFactory instanceof org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateMappingFactory
}
}