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 569a5d0dcc28277da12f6a4cccb36724fcc9b8b7 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Sep 28 15:56:13 2025 -0500 TableNameFetcher and HibernateEntityWrapper --- .../orm/hibernate/cfg/GrailsDomainBinder.java | 118 +++++++-------- .../cfg/PersistentEntityNamingStrategy.java | 10 +- .../cfg/domainbinding/CascadeBehaviorFetcher.java | 3 +- .../domainbinding/DefaultColumnNameFetcher.java | 17 +-- .../cfg/domainbinding/EnumTypeBinder.java | 2 +- .../cfg/domainbinding/HibernateEntityWrapper.java | 30 ++-- .../cfg/domainbinding/NamingStrategyWrapper.java | 15 +- .../cfg/domainbinding/TableNameFetcher.java | 34 +++++ .../grails/orm/hibernate/cfg/MappingSpec.groovy | 2 +- .../DefaultColumnNameFetcherSpec.groovy | 3 +- .../HibernateEntityWrapperSpec.groovy | 158 +++++++++++++++++++++ .../domainbinding/NamingStrategyWrapperSpec.groovy | 12 +- .../cfg/domainbinding/TableNameFetcherSpec.groovy | 38 +++++ 13 files changed, 325 insertions(+), 117 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 9bdc3c158a..51ffd13474 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 @@ -291,7 +291,7 @@ public class GrailsDomainBinder implements MetadataContributor { SimpleValue elt = new BasicValue(metadataBuildingContext, map.getCollectionTable()); map.setElement(elt); - Mapping mapping = new HibernateEntityWrapper(property.getOwner()).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(property.getOwner()); String typeName = new TypeNameProvider().getTypeName(property, mapping); if (typeName == null ) { @@ -567,7 +567,7 @@ public class GrailsDomainBinder implements MetadataContributor { TenantId tenantId = referenced.getTenantId(); if(tenantId != null) { - String defaultColumnName = new DefaultColumnNameFetcher(getNamingStrategyWrapper()).getDefaultColumnName(tenantId); + String defaultColumnName = new DefaultColumnNameFetcher(getNamingStrategy()).getDefaultColumnName(tenantId); return ":tenantId = " + defaultColumnName; } else { @@ -745,8 +745,8 @@ public class GrailsDomainBinder implements MetadataContributor { columnName = joinColumnMappingOptional.get().getName(); } else { - var clazz = namingStrategyWrapper.getColumnName(className); - var prop = namingStrategyWrapper.getTableName(property.getName()); + var clazz = getNamingStrategy().resolveColumnName(className); + var prop = getNamingStrategy().resolveTableName(property.getName()); columnName = isEnum ? clazz : new BackticksRemover().apply(prop) + UNDERSCORE + new BackticksRemover().apply(clazz); } @@ -755,7 +755,7 @@ public class GrailsDomainBinder implements MetadataContributor { } else { - Mapping mapping = new HibernateEntityWrapper(property.getOwner()).getMappedForm();; + Mapping mapping = new HibernateEntityWrapper().getMappedForm(property.getOwner());; String typeName = new TypeNameProvider().getTypeName(property, mapping); if (typeName == null) { Type type = mappings.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType(className); @@ -779,7 +779,7 @@ public class GrailsDomainBinder implements MetadataContributor { } else { final PersistentEntity domainClass = property.getAssociatedEntity(); - Mapping m = new HibernateEntityWrapper(domainClass).getMappedForm(); + Mapping m = new HibernateEntityWrapper().getMappedForm(domainClass); if (hasCompositeIdentifier(m)) { CompositeIdentity ci = (CompositeIdentity) m.getIdentity(); bindCompositeIdentifierToManyToOne(property, element, ci, domainClass, @@ -791,7 +791,7 @@ public class GrailsDomainBinder implements MetadataContributor { } else { var decapitalize = domainClass.getName(); - columnName = namingStrategyWrapper.getColumnName(decapitalize) + FOREIGN_KEY_SUFFIX; + columnName = getNamingStrategy().resolveColumnName(decapitalize) + FOREIGN_KEY_SUFFIX; } new SimpleValueColumnBinder().bindSimpleValue(element, "long", columnName, true); @@ -855,7 +855,7 @@ public class GrailsDomainBinder implements MetadataContributor { } PersistentEntity refDomainClass = property.getOwner(); - final Mapping mapping = new HibernateEntityWrapper(refDomainClass).getMappedForm(); + final Mapping mapping = new HibernateEntityWrapper().getMappedForm(refDomainClass); boolean hasCompositeIdentifier = hasCompositeIdentifier(mapping); if ((shouldCollectionBindWithJoinColumn((ToMany) property) && hasCompositeIdentifier) || (hasCompositeIdentifier && ( property instanceof ManyToMany))) { @@ -1099,7 +1099,7 @@ public class GrailsDomainBinder implements MetadataContributor { JoinTable jt = config != null ? config.getJoinTable() : null; String s = calculateTableForMany(property, sessionFactoryBeanName); - String tableName = (jt != null && jt.getName() != null ? jt.getName() : namingStrategyWrapper.getTableName(s)); + String tableName = (jt != null && jt.getName() != null ? jt.getName() : getNamingStrategy().resolveTableName(s)); String schemaName = new NamespaceNameExtractor().getSchemaName(mappings); String catalogName = new NamespaceNameExtractor().getCatalogName(mappings); @@ -1127,12 +1127,13 @@ public class GrailsDomainBinder implements MetadataContributor { * where you have two mapping tables for left_right and right_left */ private String calculateTableForMany(ToMany property, String sessionFactoryBeanName) { - String propertyColumnName = namingStrategyWrapper.getColumnName(property.getName()); + String propertyColumnName = getNamingStrategy().resolveColumnName(property.getName()); //fix for GRAILS-5895 PropertyConfig config = new PersistentPropertyToPropertyConfig().apply(property); JoinTable jt = config != null ? config.getJoinTable() : null; boolean hasJoinTableMapping = jt != null && jt.getName() != null; - String left = getTableName(property.getOwner(), sessionFactoryBeanName); + PersistentEntity domainClass1 = property.getOwner(); + String left = new TableNameFetcher(getNamingStrategy()).getTableName(domainClass1); if (Map.class.isAssignableFrom(property.getType())) { if (hasJoinTableMapping) { @@ -1152,7 +1153,8 @@ public class GrailsDomainBinder implements MetadataContributor { throw new MappingException("Expected an entity to be associated with the association (" + property + ") and none was found. "); } - String right = getTableName(property.getAssociatedEntity(), sessionFactoryBeanName); + PersistentEntity domainClass = property.getAssociatedEntity(); + String right = new TableNameFetcher(getNamingStrategy()).getTableName(domainClass); if (property instanceof ManyToMany property1) { if (hasJoinTableMapping) { @@ -1161,7 +1163,7 @@ public class GrailsDomainBinder implements MetadataContributor { if (property.isOwningSide()) { return new BackticksRemover().apply(left) + UNDERSCORE + new BackticksRemover().apply(propertyColumnName); } - String s2 = namingStrategyWrapper.getColumnName(property1.getInversePropertyName()); + String s2 = getNamingStrategy().resolveColumnName(property1.getInversePropertyName()); return new BackticksRemover().apply(right) + UNDERSCORE + new BackticksRemover().apply(s2); } @@ -1187,33 +1189,7 @@ public class GrailsDomainBinder implements MetadataContributor { return tableName; } - /** - * Evaluates the table name for the given property - * - * @param domainClass The domain class to evaluate - * @return The table name - */ - private String getTableName(PersistentEntity domainClass, String sessionFactoryBeanName) { - Mapping m = new HibernateEntityWrapper(domainClass).getMappedForm(); - String tableName = null; - if (m != null && m.getTableName() != null) { - tableName = m.getTableName(); - } - if (tableName == null) { - String shortName = domainClass.getJavaClass().getSimpleName(); - PersistentEntityNamingStrategy namingStrategy = this.namingStrategy; - - if(namingStrategy != null) { - tableName = namingStrategy.resolveTableName(domainClass); - } - if(tableName == null) { - tableName = namingStrategyWrapper.getTableName(shortName); - } - } - return tableName; - } - - public PhysicalNamingStrategy getPhysicalNamingStrategy(String sessionFactoryBeanName) { + private PhysicalNamingStrategy getPhysicalNamingStrategy(String sessionFactoryBeanName) { return NAMING_STRATEGY_PROVIDER.getPhysicalNamingStrategy(sessionFactoryBeanName); } @@ -1239,7 +1215,7 @@ public class GrailsDomainBinder implements MetadataContributor { public void evaluateMapping(PersistentEntity persistentEntity) { Optional.ofNullable(persistentEntity).ifPresent(domainClass -> { try { - final Mapping m = new HibernateEntityWrapper(domainClass).getMappedForm(); + final Mapping m = new HibernateEntityWrapper().getMappedForm(domainClass); trackCustomCascadingSaves(m, domainClass.getPersistentProperties()); AbstractGrailsDomainBinder.cacheMapping(domainClass.getJavaClass(), m); } catch (Exception e) { @@ -1312,7 +1288,6 @@ public class GrailsDomainBinder implements MetadataContributor { * @param sessionFactoryBeanName the session factory bean name */ protected void bindRoot(HibernatePersistentEntity entity, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { - this.namingStrategyWrapper = getNamingStrategyWrapper(); if (mappings.getEntityBinding(entity.getName()) != null) { LOG.info("[GrailsDomainBinder] Class [" + entity.getName() + "] is already mapped, skipping.. "); return; @@ -1329,7 +1304,7 @@ public class GrailsDomainBinder implements MetadataContributor { root.setPolymorphic(false); } else { root.setPolymorphic(true); - Mapping m = new HibernateEntityWrapper(entity).getMappedForm(); + Mapping m = new HibernateEntityWrapper().getMappedForm(entity); boolean tablePerSubclass = m != null && !m.getTablePerHierarchy(); if (!tablePerSubclass) { // if the root class has children create a discriminator property @@ -1345,8 +1320,11 @@ public class GrailsDomainBinder implements MetadataContributor { mappings.addEntityBinding(root); } - public NamingStrategyWrapper getNamingStrategyWrapper() { - return new NamingStrategyWrapper(getPhysicalNamingStrategy(sessionFactoryName), getJdbcEnvironment()); + public PersistentEntityNamingStrategy getNamingStrategy() { + if (namingStrategy == null) { + namingStrategy = new NamingStrategyWrapper(getPhysicalNamingStrategy(sessionFactoryName), getJdbcEnvironment()); + } + return namingStrategy; } /** @@ -1442,7 +1420,7 @@ public class GrailsDomainBinder implements MetadataContributor { // set the descriminator value as the name of the class. This is the // value used by Hibernate to decide what the type of the class is // to perform polymorphic queries - Mapping subMapping = new HibernateEntityWrapper(sub).getMappedForm(); + Mapping subMapping = new HibernateEntityWrapper().getMappedForm(sub); DiscriminatorConfig discriminatorConfig = subMapping != null ? subMapping.getDiscriminator() : null; subClass.setDiscriminatorValue(discriminatorConfig != null && discriminatorConfig.getValue() != null ? discriminatorConfig.getValue() : fullName); @@ -1494,7 +1472,7 @@ public class GrailsDomainBinder implements MetadataContributor { InFlightMetadataCollector mappings, String sessionFactoryBeanName) throws MappingException { classBinding.bindClass(subClass, unionSubclass, mappings); - Mapping subMapping = new HibernateEntityWrapper(subClass).getMappedForm(); + Mapping subMapping = new HibernateEntityWrapper().getMappedForm(subClass); if ( unionSubclass.getEntityPersisterClass() == null ) { unionSubclass.getRootClass().setEntityPersisterClass( @@ -1511,7 +1489,7 @@ public class GrailsDomainBinder implements MetadataContributor { Table mytable = mappings.addDenormalizedTable( schema, catalog, - getTableName(subClass, sessionFactoryBeanName), + new TableNameFetcher(getNamingStrategy()).getTableName(subClass), unionSubclass.isAbstract() != null && unionSubclass.isAbstract(), null, denormalizedSuperTable, metadataBuildingContext @@ -1570,7 +1548,7 @@ public class GrailsDomainBinder implements MetadataContributor { InFlightMetadataCollector mappings, String sessionFactoryBeanName) { String logicalTableName = unqualify(model.getEntityName()); - String physicalTableName = getTableName(sub, sessionFactoryBeanName); + String physicalTableName = new TableNameFetcher(getNamingStrategy()).getTableName(sub); String schemaName = new NamespaceNameExtractor().getSchemaName(mappings); String catalogName = new NamespaceNameExtractor().getCatalogName(mappings); @@ -1662,7 +1640,7 @@ public class GrailsDomainBinder implements MetadataContributor { RootClass root, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { // get the schema and catalog names from the configuration - Mapping m = new HibernateEntityWrapper(domainClass).getMappedForm(); + Mapping m = new HibernateEntityWrapper().getMappedForm(domainClass); configureDerivedProperties(domainClass, m); CacheConfig cc = m.getCache(); @@ -1692,7 +1670,7 @@ public class GrailsDomainBinder implements MetadataContributor { // create the table var table = mappings.addTable(schema , catalog - , getTableName(domainClass, sessionFactoryBeanName) + , new TableNameFetcher(getNamingStrategy()).getTableName(domainClass) , null , isAbstract , metadataBuildingContext @@ -1782,7 +1760,7 @@ public class GrailsDomainBinder implements MetadataContributor { private void createClassProperties(HibernatePersistentEntity domainClass, PersistentClass persistentClass, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { - Mapping gormMapping = new HibernateEntityWrapper(domainClass).getMappedForm(); + Mapping gormMapping = new HibernateEntityWrapper().getMappedForm(domainClass); Table table = persistentClass.getTable(); table.setComment(gormMapping.getComment()); final List<PersistentProperty> persistentProperties = domainClass.getPersistentProperties() @@ -2040,7 +2018,7 @@ public class GrailsDomainBinder implements MetadataContributor { private boolean isComponentPropertyNullable(PersistentProperty componentProperty) { if (componentProperty == null) return false; final HibernatePersistentEntity domainClass = (HibernatePersistentEntity) componentProperty.getOwner(); - final Mapping mapping = new HibernateEntityWrapper(domainClass).getMappedForm(); + final Mapping mapping = new HibernateEntityWrapper().getMappedForm(domainClass); return !domainClass.isRoot() && (mapping == null || mapping.isTablePerHierarchy()) || componentProperty.isNullable(); } @@ -2075,7 +2053,7 @@ public class GrailsDomainBinder implements MetadataContributor { String path, InFlightMetadataCollector mappings, String sessionFactoryBeanName) { bindManyToOneValues(property, manyToOne); PersistentEntity refDomainClass = property instanceof ManyToMany ? property.getOwner() : property.getAssociatedEntity(); - Mapping mapping = new HibernateEntityWrapper(refDomainClass).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(refDomainClass); boolean isComposite = hasCompositeIdentifier(mapping); if (isComposite) { CompositeIdentity ci = (CompositeIdentity) mapping.getIdentity(); @@ -2092,7 +2070,7 @@ public class GrailsDomainBinder implements MetadataContributor { if (!hasJoinKeyMapping(pc) ) { JoinTable jt = new JoinTable(); final ColumnConfig columnConfig = new ColumnConfig(); - columnConfig.setName(namingStrategyWrapper.getColumnName(property.getName()) + UNDERSCORE + FOREIGN_KEY_SUFFIX); + columnConfig.setName(getNamingStrategy().resolveColumnName(property.getName()) + UNDERSCORE + FOREIGN_KEY_SUFFIX); jt.setKey(columnConfig); pc.setJoinTable(jt); } @@ -2146,7 +2124,7 @@ public class GrailsDomainBinder implements MetadataContributor { // if the name is null then configure the name by convention if(cc.getName() == null) { // use the referenced table name as a prefix - String prefix = getTableName(refDomainClass, sessionFactoryBeanName); + String prefix = new TableNameFetcher(getNamingStrategy()).getTableName(refDomainClass); PersistentProperty referencedProperty = refDomainClass.getPropertyByName(propertyName); // if the referenced property is a ToOne and it has a composite id @@ -2157,10 +2135,10 @@ public class GrailsDomainBinder implements MetadataContributor { if(compositeIdentity != null) { for (PersistentProperty cip : compositeIdentity) { // for each property of a composite id by default we use the table name and the property name as a prefix - String string = namingStrategyWrapper.getColumnName(referencedProperty.getName()); + String string = getNamingStrategy().resolveColumnName(referencedProperty.getName()); String compositeIdPrefix = new BackticksRemover().apply(prefix) + UNDERSCORE + new BackticksRemover().apply(string); - String suffix = new DefaultColumnNameFetcher(getNamingStrategyWrapper()).getDefaultColumnName(cip); + String suffix = new DefaultColumnNameFetcher(getNamingStrategy()).getDefaultColumnName(cip); String finalColumnName = new BackticksRemover().apply(compositeIdPrefix) + UNDERSCORE + new BackticksRemover().apply(suffix); cc = new ColumnConfig(); cc.setName(finalColumnName); @@ -2170,7 +2148,7 @@ public class GrailsDomainBinder implements MetadataContributor { } } - String suffix = new DefaultColumnNameFetcher(getNamingStrategyWrapper()).getDefaultColumnName(referencedProperty); + String suffix = new DefaultColumnNameFetcher(getNamingStrategy()).getDefaultColumnName(referencedProperty); String finalColumnName = new BackticksRemover().apply(prefix) + UNDERSCORE + new BackticksRemover().apply(suffix); cc.setName(finalColumnName); columns.add(cc); @@ -2316,7 +2294,7 @@ public class GrailsDomainBinder implements MetadataContributor { private void bindSimpleId(PersistentProperty identifier, RootClass entity, InFlightMetadataCollector mappings, Identity mappedId, String sessionFactoryBeanName) { - Mapping mapping = new HibernateEntityWrapper(identifier.getOwner()).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(identifier.getOwner()); boolean useSequence = mapping != null && mapping.isTablePerConcreteClass(); // create the id value @@ -2397,7 +2375,7 @@ public class GrailsDomainBinder implements MetadataContributor { , String sessionFactoryBeanName ) { PropertyConfig propertyConfig = new PersistentPropertyToPropertyConfig().apply(property); - Mapping mapping = new HibernateEntityWrapper(property.getOwner()).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(property.getOwner()); final String typeName = new TypeNameProvider().getTypeName(property, mapping); if (typeName == null) { simpleValue.setTypeName(property.getType().getName()); @@ -2524,7 +2502,7 @@ public class GrailsDomainBinder implements MetadataContributor { final PersistentEntity owner = property.getOwner(); if (!owner.isRoot()) { - Mapping mapping = new HibernateEntityWrapper(owner).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(owner); if (mapping == null || mapping.getTablePerHierarchy()) { if (LOG.isDebugEnabled()) LOG.debug("[GrailsDomainBinder] Sub class property [" + property.getName() + "] for column name ["+column.getName()+"] set to nullable"); @@ -2564,7 +2542,7 @@ public class GrailsDomainBinder implements MetadataContributor { if (cc == null) { // No column config given, so try to fetch it from the mapping PersistentEntity domainClass = grailsProp.getOwner(); - Mapping m = new HibernateEntityWrapper(domainClass).getMappedForm(); + Mapping m = new HibernateEntityWrapper().getMappedForm(domainClass); if (m != null) { PropertyConfig c = m.getPropertyConfig(grailsProp.getName()); @@ -2593,13 +2571,13 @@ public class GrailsDomainBinder implements MetadataContributor { if (columnName == null) { if (isNotEmpty(path)) { - String s1 = namingStrategyWrapper.getColumnName(path); + String s1 = getNamingStrategy().resolveColumnName(path); - String s2 = new DefaultColumnNameFetcher(getNamingStrategyWrapper()).getDefaultColumnName(grailsProp); + String s2 = new DefaultColumnNameFetcher(getNamingStrategy()).getDefaultColumnName(grailsProp); columnName = new BackticksRemover().apply(s1) + UNDERSCORE + new BackticksRemover().apply(s2); } else { - columnName = new DefaultColumnNameFetcher(getNamingStrategyWrapper()).getDefaultColumnName(grailsProp); + columnName = new DefaultColumnNameFetcher(getNamingStrategy()).getDefaultColumnName(grailsProp); } } return columnName; @@ -2618,13 +2596,13 @@ public class GrailsDomainBinder implements MetadataContributor { if (pc != null && pc.getIndexColumn() != null && pc.getIndexColumn().getColumn() != null) { return pc.getIndexColumn().getColumn(); } - return namingStrategyWrapper.getColumnName(property.getName()) + UNDERSCORE + IndexedCollection.DEFAULT_INDEX_COLUMN_NAME; + return getNamingStrategy().resolveColumnName(property.getName()) + UNDERSCORE + IndexedCollection.DEFAULT_INDEX_COLUMN_NAME; } private String getIndexColumnType(PersistentProperty property, String defaultType) { PropertyConfig pc = new PersistentPropertyToPropertyConfig().apply(property); if (pc != null && pc.getIndexColumn() != null && pc.getIndexColumn().getType() != null) { - Mapping mapping =new HibernateEntityWrapper(property.getOwner()).getMappedForm(); + Mapping mapping =new HibernateEntityWrapper().getMappedForm(property.getOwner()); return new TypeNameProvider().getTypeName(property, mapping); } return defaultType; @@ -2636,7 +2614,7 @@ public class GrailsDomainBinder implements MetadataContributor { if (hasJoinTableColumnNameMapping(pc)) { return pc.getJoinTable().getColumn().getName(); } - return namingStrategyWrapper.getColumnName(property.getName()) + UNDERSCORE + IndexedCollection.DEFAULT_ELEMENT_COLUMN_NAME; + return getNamingStrategy().resolveColumnName(property.getName()) + UNDERSCORE + IndexedCollection.DEFAULT_ELEMENT_COLUMN_NAME; } private boolean hasJoinTableColumnNameMapping(PropertyConfig pc) { @@ -2867,7 +2845,7 @@ public class GrailsDomainBinder implements MetadataContributor { } public String getTypeName(ToMany property) { - Mapping mapping = new HibernateEntityWrapper(property.getOwner()).getMappedForm(); + Mapping mapping = new HibernateEntityWrapper().getMappedForm(property.getOwner()); return new TypeNameProvider().getTypeName(property, mapping); } diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/PersistentEntityNamingStrategy.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/PersistentEntityNamingStrategy.java index 70a5935fed..0180a52853 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/PersistentEntityNamingStrategy.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/PersistentEntityNamingStrategy.java @@ -1,6 +1,7 @@ package org.grails.orm.hibernate.cfg; import org.grails.datastore.mapping.model.PersistentEntity; +import org.grails.datastore.mapping.model.PersistentProperty; /** * Allows plugging into to custom naming strategies @@ -10,6 +11,13 @@ import org.grails.datastore.mapping.model.PersistentEntity; */ public interface PersistentEntityNamingStrategy { - String resolveTableName(PersistentEntity entity); + String resolveColumnName(String logicalName); + default String resolveTableName(PersistentEntity entity){ + return resolveTableName(entity.getJavaClass().getSimpleName()); + } + + String resolveTableName(String logicalName); + + String resolveForeignKeyForPropertyDomainClass(PersistentProperty property); } diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/CascadeBehaviorFetcher.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/CascadeBehaviorFetcher.java index 285ec5d162..336d00681b 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/CascadeBehaviorFetcher.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/CascadeBehaviorFetcher.java @@ -84,8 +84,7 @@ public class CascadeBehaviorFetcher { } private Mapping getOwnersWrappedForm(Association<?> association) { - return new HibernateEntityWrapper(association.getOwner()) - .getMappedForm(); + return new HibernateEntityWrapper().getMappedForm(association.getOwner()); } diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java index 8a1dc3f2a5..84ab7f0907 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcher.java @@ -4,28 +4,29 @@ import org.grails.datastore.mapping.model.PersistentProperty; import org.grails.datastore.mapping.model.types.Association; import org.grails.datastore.mapping.model.types.Basic; import org.grails.datastore.mapping.model.types.ManyToMany; +import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy; public class DefaultColumnNameFetcher { private static final String FOREIGN_KEY_SUFFIX = "_id"; private static final String UNDERSCORE = "_"; - private final NamingStrategyWrapper namingStrategyWrapper; + private final PersistentEntityNamingStrategy namingStrategyWrapper; private final BackticksRemover backticksRemover; - public DefaultColumnNameFetcher( NamingStrategyWrapper namingStrategyWrapper) { + public DefaultColumnNameFetcher( PersistentEntityNamingStrategy namingStrategyWrapper) { this.namingStrategyWrapper = namingStrategyWrapper; this.backticksRemover = new BackticksRemover(); } - protected DefaultColumnNameFetcher(NamingStrategyWrapper namingStrategyWrapper , BackticksRemover backticksRemover) { + protected DefaultColumnNameFetcher(PersistentEntityNamingStrategy namingStrategyWrapper , BackticksRemover backticksRemover) { this.namingStrategyWrapper = namingStrategyWrapper; this.backticksRemover = backticksRemover; } public String getDefaultColumnName(PersistentProperty property) { - String columnName = namingStrategyWrapper.getColumnName(property.getName()); + String columnName = namingStrategyWrapper.resolveColumnName(property.getName()); if (property instanceof Association) { Association association = (Association) property; boolean isBasic = property instanceof Basic; @@ -34,20 +35,20 @@ public class DefaultColumnNameFetcher { } if (isBasic) { - return namingStrategyWrapper.getForeignKeyForPropertyDomainClass(property); + return namingStrategyWrapper.resolveForeignKeyForPropertyDomainClass(property); } if (property instanceof ManyToMany) { - return namingStrategyWrapper.getForeignKeyForPropertyDomainClass(property); + return namingStrategyWrapper.resolveForeignKeyForPropertyDomainClass(property); } if (!association.isBidirectional() && association instanceof org.grails.datastore.mapping.model.types.OneToMany) { - String prefix = namingStrategyWrapper.getTableName(property.getOwner().getName()); + String prefix = namingStrategyWrapper.resolveTableName(property.getOwner().getName()); return backticksRemover.apply(prefix) + UNDERSCORE + backticksRemover.apply(columnName) + FOREIGN_KEY_SUFFIX; } if (property.isInherited() && property.isBidirectionalManyToOne()) { - return namingStrategyWrapper.getColumnName(property.getOwner().getName()) + '_' + columnName + FOREIGN_KEY_SUFFIX; + return namingStrategyWrapper.resolveColumnName(property.getOwner().getName()) + '_' + columnName + FOREIGN_KEY_SUFFIX; } return columnName + FOREIGN_KEY_SUFFIX; diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java index 6a2de0ee0e..db7c036a1e 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/EnumTypeBinder.java @@ -41,7 +41,7 @@ public class EnumTypeBinder { public void bindEnumType(PersistentProperty property, Class<?> propertyType, SimpleValue simpleValue, String columnName) { PropertyConfig pc = new PersistentPropertyToPropertyConfig().apply(property); - Mapping ownerMapping = new HibernateEntityWrapper(property.getOwner()).getMappedForm(); + Mapping ownerMapping = new HibernateEntityWrapper().getMappedForm(property.getOwner()); String enumType = pc.getEnumType(); Properties enumProperties = new Properties(); enumProperties.put(ENUM_CLASS_PROP, propertyType.getName()); diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapper.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapper.java index d9242ed52b..76c6525603 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapper.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapper.java @@ -9,35 +9,23 @@ import org.hibernate.MappingException; import java.util.Optional; +import jakarta.annotation.Nonnull; + /** * This class exists because Embedded Entities do not inherit * from HibernatePersistentEntity but have similar functionality. */ public class HibernateEntityWrapper { - private HibernatePersistentEntity hibernatePersistentEntity; - private HibernateMappingContext.HibernateEmbeddedPersistentEntity hibernateEmbeddedPersistentEntity; - - public HibernateEntityWrapper(PersistentEntity hibernatePersistentEntity) { - if (hibernatePersistentEntity instanceof HibernatePersistentEntity) { - this.hibernatePersistentEntity = (HibernatePersistentEntity) hibernatePersistentEntity; - } else if (hibernatePersistentEntity instanceof HibernateMappingContext.HibernateEmbeddedPersistentEntity) { - this.hibernateEmbeddedPersistentEntity = (HibernateMappingContext.HibernateEmbeddedPersistentEntity) hibernatePersistentEntity; + @Nonnull + public Mapping getMappedForm(PersistentEntity persistentEntity) { + if (persistentEntity instanceof HibernatePersistentEntity _hibernatePersistentEntity) { + return _hibernatePersistentEntity.getMappedForm(); + } else if (persistentEntity instanceof HibernateMappingContext.HibernateEmbeddedPersistentEntity embedded) { + return embedded.getMappedForm(); } else { - throw new MappingException("Not correct Persistent Entity "+ hibernatePersistentEntity.getClass()); + throw new MappingException("Not correct Persistent Entity"); } } - - public Mapping getMappedForm() { - if (hibernatePersistentEntity != null) { - return hibernatePersistentEntity.getMappedForm(); - } else if (hibernateEmbeddedPersistentEntity != null) { - return hibernateEmbeddedPersistentEntity.getMappedForm(); - } else { - throw new MappingException("Not correct Persistent Entity"); - } - } - - } diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java index b4a7baa831..6099c49e95 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapper.java @@ -3,6 +3,8 @@ package org.grails.orm.hibernate.cfg.domainbinding; import org.grails.datastore.mapping.model.PersistentEntity; import org.grails.datastore.mapping.model.PersistentProperty; import org.grails.datastore.mapping.reflect.NameUtils; +import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy; + import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -16,7 +18,7 @@ import static org.hibernate.boot.model.naming.Identifier.toIdentifier; * A wrapper for the Hibernate 6 PhysicalNamingStrategy to adapt it * for use within the Grails binding process, using a functional style. */ -public class NamingStrategyWrapper { +public class NamingStrategyWrapper implements PersistentEntityNamingStrategy { private final PhysicalNamingStrategy namingStrategy; private final JdbcEnvironment jdbcEnvironment; @@ -32,7 +34,8 @@ public class NamingStrategyWrapper { this.jdbcEnvironment = jdbcEnvironment; } - public String getColumnName(String logicalName) { + @Override + public String resolveColumnName(String logicalName) { return Optional.ofNullable(logicalName) .flatMap(name -> // Safely handle a null return from the strategy by wrapping it in an Optional. @@ -43,7 +46,8 @@ public class NamingStrategyWrapper { .orElse(logicalName); } - public String getTableName(String logicalName) { + @Override + public String resolveTableName(String logicalName) { return Optional.ofNullable(logicalName) .flatMap(name -> // Safely handle a null return from the strategy. @@ -54,13 +58,14 @@ public class NamingStrategyWrapper { .orElse(logicalName); } - public String getForeignKeyForPropertyDomainClass(PersistentProperty property) { + @Override + public String resolveForeignKeyForPropertyDomainClass(PersistentProperty property) { return Optional.ofNullable(property) .map(PersistentProperty::getOwner) .map(PersistentEntity::getJavaClass) .map(Class::getSimpleName) .map(NameUtils::decapitalize) - .map(this::getColumnName) + .map(this::resolveColumnName) .filter(name -> !name.isBlank()) .map(columnName -> columnName + FOREIGN_KEY_SUFFIX) .orElse(null); diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcher.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcher.java new file mode 100644 index 0000000000..f826f5726e --- /dev/null +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcher.java @@ -0,0 +1,34 @@ +package org.grails.orm.hibernate.cfg.domainbinding; + +import java.util.Optional; + +import org.grails.datastore.mapping.model.PersistentEntity; +import org.grails.orm.hibernate.cfg.Mapping; +import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy; + +/** + * Evaluates the table name for the given property + * + * @param domainClass The domain class to evaluate + * @return The table name + */ +public class TableNameFetcher { + + private final PersistentEntityNamingStrategy persistentEntityNamingStrategy; + private final HibernateEntityWrapper hibernateEntityWrapper; + + public TableNameFetcher(PersistentEntityNamingStrategy persistentEntityNamingStrategy) { + this.persistentEntityNamingStrategy = persistentEntityNamingStrategy; + this.hibernateEntityWrapper = new HibernateEntityWrapper(); + } + + protected TableNameFetcher(PersistentEntityNamingStrategy persistentEntityNamingStrategy, HibernateEntityWrapper hibernateEntityWrapper) { + this.persistentEntityNamingStrategy = persistentEntityNamingStrategy; + this.hibernateEntityWrapper = hibernateEntityWrapper; + } + + public String getTableName(PersistentEntity domainClass) { + var tableName = hibernateEntityWrapper.getMappedForm(domainClass).getTableName(); + return tableName != null ? tableName :persistentEntityNamingStrategy.resolveTableName(domainClass); + } +} diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/MappingSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/MappingSpec.groovy index 30e9ca65e3..4eceb13502 100644 --- a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/MappingSpec.groovy +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/MappingSpec.groovy @@ -17,7 +17,7 @@ class MappingSpec extends HibernateGormDatastoreSpec { // Ensure all related entities are processed by the mapping context createPersistentEntity(Author, binder) def entity = createPersistentEntity(domainClass, binder) - def mapping = new HibernateEntityWrapper(entity).getMappedForm() + def mapping = new HibernateEntityWrapper().getMappedForm(entity) def property = entity.getPropertyByName(propertyName) when: "The method is called on the mapping object" diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy index 768267005f..43b9a496a4 100644 --- a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/DefaultColumnNameFetcherSpec.groovy @@ -1,6 +1,5 @@ package org.grails.orm.hibernate.cfg.domainbinding -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment import grails.gorm.annotation.Entity import grails.gorm.specs.HibernateGormDatastoreSpec @@ -12,7 +11,7 @@ class DefaultColumnNameFetcherSpec extends HibernateGormDatastoreSpec { @Unroll void "Test getDefaultColumnName for #description"() { given: - def namingStrategy =grailsDomainBinder.getNamingStrategyWrapper() + def namingStrategy =grailsDomainBinder.getNamingStrategy() def backticksRemover = new BackticksRemover() def fetcher = new DefaultColumnNameFetcher(namingStrategy, backticksRemover) diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapperSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapperSpec.groovy new file mode 100644 index 0000000000..7395b13472 --- /dev/null +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/HibernateEntityWrapperSpec.groovy @@ -0,0 +1,158 @@ +package org.grails.orm.hibernate.cfg.domainbinding + +import org.grails.datastore.mapping.model.ClassMapping +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.types.Association +import org.grails.datastore.mapping.model.types.Embedded +import org.grails.datastore.mapping.model.types.TenantId +import org.grails.datastore.mapping.reflect.EntityReflector +import org.grails.orm.hibernate.cfg.HibernateMappingContext +import org.grails.orm.hibernate.cfg.HibernatePersistentEntity +import org.grails.orm.hibernate.cfg.Mapping +import org.hibernate.MappingException +import spock.lang.Specification + +class HibernateEntityWrapperSpec extends Specification { + + def "Test getMappedForm with different PersistentEntity types"() { + given: + def wrapper = new HibernateEntityWrapper() + + and: "a mock HibernatePersistentEntity" + def hibernateEntity = Mock(HibernatePersistentEntity) + def hibernateMapping = Mock(Mapping) + hibernateEntity.getMappedForm() >> hibernateMapping + + and: "a mock HibernateEmbeddedPersistentEntity" + def embeddedEntity = Mock(HibernateMappingContext.HibernateEmbeddedPersistentEntity) + def embeddedMapping = Mock(Mapping) + embeddedEntity.getMappedForm() >> embeddedMapping + + and: "a generic PersistentEntity implementation" + def genericEntity = new TestPersistentEntity() + + when: "getMappedForm is called with a HibernatePersistentEntity" + def resultForHibernateEntity = wrapper.getMappedForm(hibernateEntity) + + then: "it returns the correct mapping" + resultForHibernateEntity == hibernateMapping + + when: "getMappedForm is called with a HibernateEmbeddedPersistentEntity" + def resultForEmbeddedEntity = wrapper.getMappedForm(embeddedEntity) + + then: "it returns the correct mapping" + resultForEmbeddedEntity == embeddedMapping + + when: "getMappedForm is called with a generic PersistentEntity" + wrapper.getMappedForm(genericEntity) + + then: "a MappingException is thrown" + thrown(MappingException) + } + + // Helper class for the exception test + private static class TestPersistentEntity implements PersistentEntity { + @Override + String getName() { + return "TestEntity" + } + + // Other methods can return null or default values as they are not called + @Override + Class getJavaClass() { return null } + @Override + boolean isInstance(Object obj) { return false } + @Override + String getDecapitalizedName() { return null } + @Override + List<String> getPersistentPropertyNames() { return [] } + @Override + List<PersistentProperty> getPersistentProperties() { return [] } + @Override + List<Association> getAssociations() { return [] } + + @Override + List<Embedded> getEmbedded() { + return null + } + + @Override + PersistentProperty getPropertyByName(String name) { return null } + @Override + PersistentProperty getIdentity() { return null } + @Override + PersistentProperty getVersion() { return null } + @Override + boolean isVersioned() { return false } + + + @Override + TenantId getTenantId() { + return null + } + + + @Override + PersistentEntity getParentEntity() { return null } + @Override + PersistentEntity getRootEntity() { return null } + @Override + boolean isRoot() { return false } + @Override + String getDiscriminator() { return null } + @Override + boolean isOwningEntity(PersistentEntity owner) { return false } + @Override + Object newInstance() { return null } + @Override + void initialize() { } + + @Override + boolean isInitialized() { + return false + } + + @Override + MappingContext getMappingContext() { return null } + + @Override + boolean hasProperty(String name, Class type) { + return false + } + + @Override + boolean isIdentityName(String propertyName) { + return false + } + + @Override + EntityReflector getReflector() { + return null + } + + @Override + boolean addOwner(Class type) { + return false + } + + @Override + boolean isExternal() { return false } + + @Override + boolean isMultiTenant() { + return false + } + + @Override + PersistentProperty[] getCompositeIdentity() { + return null + } + + @Override + void setExternal(boolean external) { } + @Override + ClassMapping getMapping() { return null } + } +} diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy index 07e5aa88fb..29a7fba47a 100644 --- a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/NamingStrategyWrapperSpec.groovy @@ -51,7 +51,7 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { "jdbcEnv" | Mock(PhysicalNamingStrategy) | null } - def "should delegate getColumnName to the wrapped strategy"() { + def 'should delegate resolveColumnName to the wrapped strategy'() { given: "A logical column name and a captured argument" def logicalName = "firstName" def expectedPhysicalName = "first_name" @@ -64,7 +64,7 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { } when: "The wrapper's getColumnName method is called" - def actualResult = wrapper.getColumnName(logicalName) + def actualResult = wrapper.resolveColumnName(logicalName) then: "The result from the wrapped strategy is returned" actualResult == expectedPhysicalName @@ -81,13 +81,13 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { mockStrategy.toPhysicalColumnName(_, mockJdbcEnv) >> null when: "The wrapper's getColumnName method is called" - def actualResult = wrapper.getColumnName(logicalName) + def actualResult = wrapper.resolveColumnName(logicalName) then: "The original logical name is returned, fulfilling the contract" actualResult == logicalName } - def "should delegate getTableName to the wrapped strategy"() { + def 'should delegate resolveTableName to the wrapped strategy'() { given: "A logical table name and a captured argument" def logicalName = "MyTable" def expectedPhysicalName = "my_table" @@ -100,7 +100,7 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { } when: "The wrapper's getTableName method is called" - def actualResult = wrapper.getTableName(logicalName) + def actualResult = wrapper.resolveTableName(logicalName) then: "The result from the wrapped strategy is returned" actualResult == expectedPhysicalName @@ -124,7 +124,7 @@ class NamingStrategyWrapperSpec extends HibernateGormDatastoreSpec { } when: "getForeignKeyForPropertyDomainClass is called" - def actualFkName = wrapper.getForeignKeyForPropertyDomainClass(property) + def actualFkName = wrapper.resolveForeignKeyForPropertyDomainClass(property) then: "The final name is the physical column name plus the standard suffix" actualFkName == physicalColumnName + FOREIGN_KEY_SUFFIX diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcherSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcherSpec.groovy new file mode 100644 index 0000000000..2b1901b2ab --- /dev/null +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/TableNameFetcherSpec.groovy @@ -0,0 +1,38 @@ +package org.grails.orm.hibernate.cfg.domainbinding + +import org.grails.datastore.mapping.model.PersistentEntity +import org.grails.orm.hibernate.cfg.Mapping +import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy +import spock.lang.Specification +import spock.lang.Unroll + +class TableNameFetcherSpec extends Specification { + + @Unroll + def "Test getTableName when mapped form returns '#tableName'"() { + given: + def namingStrategy = Mock(PersistentEntityNamingStrategy) + def hibernateEntityWrapper = Mock(HibernateEntityWrapper) + def fetcher = new TableNameFetcher(namingStrategy, hibernateEntityWrapper) + def persistentEntity = Mock(PersistentEntity) + def mapping = Mock(Mapping) + + // Setup: getMappedForm always returns a valid Mapping object, per its contract + hibernateEntityWrapper.getMappedForm(persistentEntity) >> mapping + // The table name from the mapping can be explicit or null + mapping.getTableName() >> tableName + // The naming strategy will provide a fallback + namingStrategy.resolveTableName(persistentEntity) >> "strategy_table_name" + + when: + String result = fetcher.getTableName(persistentEntity) + + then: + result == expectedResult + + where: + scenario | tableName | expectedResult + "explicit table name" | "explicit_table_name" | "explicit_table_name" + "null table name" | null | "strategy_table_name" + } +}
