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 da832c7ae6ba89f02fc087d67c3c52de67648f6c
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Sun Feb 22 17:45:12 2026 -0600

    CompileStatic HibernateMappingBuilder
---
 .../hibernate/HibernateMappingBuilder.groovy       | 635 +++++++--------------
 1 file changed, 196 insertions(+), 439 deletions(-)

diff --git 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingBuilder.groovy
 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingBuilder.groovy
index 048ccc2489..cb991a1439 100644
--- 
a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingBuilder.groovy
+++ 
b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/hibernate/HibernateMappingBuilder.groovy
@@ -5,11 +5,10 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * http://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.
+ * 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.
  */
@@ -22,14 +21,12 @@ import 
org.grails.datastore.mapping.reflect.ClassPropertyFetcher
 import org.hibernate.FetchMode
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
-
 import jakarta.persistence.AccessType
-
 import org.grails.orm.hibernate.cfg.CacheConfig
+import org.grails.orm.hibernate.cfg.SortConfig
 import org.grails.orm.hibernate.cfg.ColumnConfig
 import org.grails.orm.hibernate.cfg.CompositeIdentity
 import org.grails.orm.hibernate.cfg.Identity
-import org.grails.orm.hibernate.cfg.JoinTable
 import org.grails.orm.hibernate.cfg.Mapping
 import org.grails.orm.hibernate.cfg.NaturalId
 import org.grails.orm.hibernate.cfg.PropertyConfig
@@ -42,8 +39,8 @@ import org.grails.orm.hibernate.cfg.PropertyDefinitionDelegate
  * @author Graeme Rocher
  * @since 1.0
  */
-
-class HibernateMappingBuilder implements MappingConfigurationBuilder<Mapping, 
PropertyConfig>{
+@CompileStatic
+class HibernateMappingBuilder implements MappingConfigurationBuilder<Mapping, 
PropertyConfig> {
 
     private static final String INCLUDE_PARAM = 'include'
     private static final String EXCLUDE_PARAM = 'exclude'
@@ -56,11 +53,6 @@ class HibernateMappingBuilder implements 
MappingConfigurationBuilder<Mapping, Pr
     private List<String> methodMissingExcludes = []
     private List<String> methodMissingIncludes
 
-    /**
-     * Constructor for builder
-     *
-     * @param className The name of the class being mapped
-     */
     HibernateMappingBuilder(String className) {
         this.className = className
     }
@@ -76,121 +68,70 @@ class HibernateMappingBuilder implements 
MappingConfigurationBuilder<Mapping, Pr
         return mapping.columns
     }
 
-    /**
-     * Central entry point for the class. Passing a closure that defines a set 
of mappings will evaluate said mappings
-     * and populate the "mapping" property of this class which can then be 
obtained with getMappings()
-     *
-     * @param mappingClosure The closure that defines the ORM DSL
-     */
-
     @Override
-    @CompileStatic
-    Mapping evaluate(Closure mappingClosure, Object context = null) {
+    Mapping evaluate(@DelegatesTo(value = HibernateMappingBuilder, strategy = 
Closure.DELEGATE_ONLY) Closure mappingClosure, Object context = null) {
         if (mapping == null) {
             mapping = new Mapping()
         }
         mappingClosure.resolveStrategy = Closure.DELEGATE_ONLY
         mappingClosure.delegate = this
         try {
-            if(context != null) {
+            if (context != null) {
                 mappingClosure.call(context)
-            }
-            else {
+            } else {
                 mappingClosure.call()
             }
-        }
-        finally {
+        } finally {
             mappingClosure.delegate = null
         }
         mapping
     }
-    /**
-     * Include another config in this one
-     */
-    @CompileStatic
-    void includes(Closure callable) {
+
+    void includes(@DelegatesTo(value = HibernateMappingBuilder, strategy = 
Closure.DELEGATE_ONLY) Closure callable) {
         if (!callable) {
             return
         }
-
         callable.resolveStrategy = Closure.DELEGATE_ONLY
         callable.delegate = this
         try {
             callable.call()
-        }
-        finally {
+        } finally {
             callable.delegate = null
         }
     }
-    @CompileStatic
+
     void hibernateCustomUserType(Map args) {
         if (args.type && (args['class'] instanceof Class)) {
-            mapping.userTypes[args['class']] = args.type
+            mapping.userTypes[(Class)args['class']] = args.type.toString()
         }
     }
 
-    /**
-     * <p>Configures the table name. Example:
-     * <code> { table 'foo' }
-     *
-     * @param name The name of the table
-     */
-    @CompileStatic
     void table(String name) {
         mapping.tableName = name
     }
 
-    /**
-    * <p>Configures the discriminator name. Example:
-    * <code> { discriminator 'foo' }
-    *
-    * @param name The name of the table
-    */
-    @CompileStatic
     void discriminator(String name) {
         mapping.discriminator(name)
     }
 
-    /**
-     * <p>Configures the discriminator name. Example:
-     * <code> { discriminator value:'foo', column:'type' }
-     *
-     * @param name The name of the table
-     */
-    @CompileStatic
     void discriminator(Map args) {
         mapping.discriminator(args)
     }
 
-    /**
-     * <p>Configures whether to auto import packages domain classes in HQL 
queries. Default is true
-     * <code> { autoImport false }
-     */
-    @CompileStatic
     void autoImport(boolean b) {
         mapping.autoImport = b
     }
 
-    /**
-     * <p>Configures the table name. Example:
-     * <code> { table name:'foo', schema:'dbo', catalog:'CRM' }
-     */
-    @CompileStatic
     void table(Map tableDef) {
         mapping.table.name = tableDef?.name?.toString()
         mapping.table.schema = tableDef?.schema?.toString()
         mapping.table.catalog = tableDef?.catalog?.toString()
     }
 
-    /**
-     * <p>Configures the default sort column. Example:
-     * <code> { sort 'foo' }
-     *
-     * @param name The name of the property to sort by
-     */
     void sort(String name) {
         if (name) {
-            mapping.getSort().name = name
+            SortConfig sc = (SortConfig) mapping.getSort()
+            sc.name = name
         }
     }
 
@@ -198,510 +139,326 @@ class HibernateMappingBuilder implements 
MappingConfigurationBuilder<Mapping, Pr
         mapping.autowire = autowire
     }
 
-    /**
-     * Whether to use dynamic update queries
-     */
-    @CompileStatic
     void dynamicUpdate(boolean b) {
         mapping.dynamicUpdate = b
     }
 
-    /**
-     * Whether to use dynamic update queries
-     */
-    @CompileStatic
     void dynamicInsert(boolean b) {
         mapping.dynamicInsert = b
     }
 
-    /**
-     * <p>Configures the default sort column. Example:
-     * <code> { sort foo:'desc' }
-     *
-     * @param namesAndDirections The names and directions of the property to 
sort by
-     */
     void sort(Map namesAndDirections) {
         if (namesAndDirections) {
-            mapping.getSort().namesAndDirections = namesAndDirections
+            SortConfig sc = (SortConfig) mapping.getSort()
+            sc.namesAndDirections = (Map<String, String>)namesAndDirections
         }
     }
 
-    /**
-     * Configures the batch-size used for lazy loading
-     * @param num The batch size to use
-     */
-    @CompileStatic
     void batchSize(Integer num) {
         if (num) {
             mapping.batchSize = num
         }
     }
 
-    /**
-     * <p>Configures the default sort direction. Example:
-     * <code> { order 'desc' }
-     *
-     * @param name The name of the property to sort by
-     */
     void order(String direction) {
         if ("desc".equalsIgnoreCase(direction) || 
"asc".equalsIgnoreCase(direction)) {
-            mapping.getSort().direction = direction
+            SortConfig sc = (SortConfig) mapping.getSort()
+            sc.direction = direction
         }
     }
 
-    /**
-     * Set whether auto time stamping should occur for last_updated and 
date_created columns
-     */
-    @CompileStatic
     void autoTimestamp(boolean b) {
         mapping.autoTimestamp = b
     }
 
-    /**
-     * <p>Configures whether to use versioning for optimistic locking
-     * <code> { version false }
-     *
-     * @param isVersioned True if a version property should be configured
-     */
-    @CompileStatic
     void version(boolean isVersioned) {
         mapping.version(isVersioned)
     }
 
-    /**
-     * <p>Configures the name of the version column
-     * <code> { version 'foo' }
-     *
-     * @param isVersioned True if a version property should be configured
-     */
-    @CompileStatic
     void version(String versionColumn) {
         mapping.version(versionColumn)
     }
 
-    /**
-     * Sets the tenant id
-     *
-     * @param tenantIdProperty The tenant id property
-     */
     void tenantId(String tenantIdProperty) {
         mapping.tenantId(tenantIdProperty)
     }
 
-    /**
-     * <p>Configures the second-level cache for the class
-     * <code> { cache usage:'read-only', include:'all' }
-     *
-     * @param args Named arguments that contain the "usage" and/or "include" 
parameters
-     */
-    @CompileStatic
     void cache(Map args) {
-        mapping.cache = new CacheConfig(enabled:true)
+        mapping.cache = new CacheConfig(enabled: true)
         if (args.usage) {
-            if (CacheConfig.USAGE_OPTIONS.contains(args.usage)) {
-                mapping.cache.usage = args.usage
-            }
-            else {
-                LOG.warn("ORM Mapping Invalid: Specified [usage] with value 
[$args.usage] of [cache] in class [$className] is not valid")
+            String usage = args.usage.toString()
+            if (CacheConfig.USAGE_OPTIONS.contains(usage)) {
+                mapping.cache.usage = usage
+            } else {
+                LOG.warn("ORM Mapping Invalid: Specified [usage] with value 
[$usage] of [cache] in class [$className] is not valid")
             }
         }
         if (args.include) {
-            if (CacheConfig.INCLUDE_OPTIONS.contains(args.include)) {
-                mapping.cache.include = args.include
-            }
-            else {
-                LOG.warn("ORM Mapping Invalid: Specified [include] with value 
[$args.include] of [cache] in class [$className] is not valid")
+            String include = args.include.toString()
+            if (CacheConfig.INCLUDE_OPTIONS.contains(include)) {
+                mapping.cache.include = include
+            } else {
+                LOG.warn("ORM Mapping Invalid: Specified [include] with value 
[$include] of [cache] in class [$className] is not valid")
             }
         }
     }
 
-    /**
-     * <p>Configures the second-level cache for the class
-     * <code> { cache 'read-only' }
-     *
-     * @param usage The usage type for the cache which is one of 
CacheConfig.USAGE_OPTIONS
-     */
-    @CompileStatic
     void cache(String usage) {
-        cache(usage:usage)
+        cache(usage: usage)
     }
 
-    /**
-     * <p>Configures the second-level cache for the class
-     * <code> { cache 'read-only', include:'all }
-     *
-     * @param usage The usage type for the cache which is one of 
CacheConfig.USAGE_OPTIONS
-     */
-    @CompileStatic
     void cache(String usage, Map args) {
-        args = args ? args : [:]
-        args.usage = usage
-        cache(args)
+        Map finalArgs = args ? new HashMap(args) : [:]
+        finalArgs.usage = usage
+        cache(finalArgs)
     }
 
-    /**
-     * If true the class and its sub classes will be mapped with table per 
hierarchy mapping
-     */
-    @CompileStatic
     void tablePerHierarchy(boolean isTablePerHierarchy) {
         mapping.tablePerHierarchy = isTablePerHierarchy
     }
 
-    /**
-     * If true the class and its subclasses will be mapped with table per 
subclass mapping
-     */
-    @CompileStatic
     void tablePerSubclass(boolean isTablePerSubClass) {
         mapping.tablePerHierarchy = !isTablePerSubClass
     }
 
-    /**
-     * If true the class and its subclasses will be mapped with table per 
subclass mapping
-     */
-    @CompileStatic
     void tablePerConcreteClass(boolean isTablePerConcreteClass) {
-        if(isTablePerConcreteClass) {
+        if (isTablePerConcreteClass) {
             mapping.tablePerHierarchy = false
             mapping.tablePerConcreteClass = true
         }
     }
 
-
-    /**
-     * <p>Configures the second-level cache with the default usage of 
'read-write' and the default include of 'all' if
-     *  the passed argument is true
-     *
-     * <code> { cache true }
-     *
-     * @param shouldCache True if the default cache configuration should be 
applied
-     */
-    @CompileStatic
     void cache(boolean shouldCache) {
-        mapping.cache = new CacheConfig(enabled:shouldCache)
+        mapping.cache = new CacheConfig(enabled: shouldCache)
     }
 
-    /**
-     * <p>Configures the identity strategy for the mapping. Examples
-     *
-     * <code>
-     *    { id generator:'sequence' }
-     *    { id composite: ['one', 'two'] }
-     * </code>
-     *
-     * @param args The named arguments to the id method
-     */
     void id(Map args) {
         if (args.composite) {
-            mapping.identity = new 
CompositeIdentity(propertyNames:args.composite as String[])
+            mapping.identity = new CompositeIdentity(propertyNames: (String[]) 
args.composite)
             if (args.compositeClass) {
-                ((CompositeIdentity)mapping.identity).compositeClass = 
(Class)args.compositeClass
+                (mapping.identity as CompositeIdentity).compositeClass = 
(Class) args.compositeClass
             }
-        }
-        else {
+        } else {
             if (args?.generator) {
-                ((Identity)mapping.identity).generator = 
args.remove('generator').toString()
+                ((Identity) mapping.identity).generator = 
args.remove('generator').toString()
             }
             if (args?.name) {
-                ((Identity)mapping.identity).name = 
args.remove('name').toString()
+                ((Identity) mapping.identity).name = 
args.remove('name').toString()
             }
             if (args?.params) {
-                def params = (Map)args.remove('params')
-                for (entry in params) {
-                    params[entry.key] = entry.value?.toString()
-                }
-                ((Identity)mapping.identity).params = params
+                Map params = (Map) args.remove('params')
+                Map<String, String> stringParams = [:]
+                params.each { k, v -> stringParams[k.toString()] = 
v?.toString() }
+                ((Identity) mapping.identity).params = stringParams
             }
         }
         if (args?.natural) {
-            def naturalArgs = args.remove('natural')
-            def propertyNames = naturalArgs instanceof Map ? 
((Map)naturalArgs).remove('properties') : naturalArgs
-
+            Object naturalArgs = args.remove('natural')
+            Object propertyNames = naturalArgs instanceof Map ? ((Map) 
naturalArgs).remove('properties') : naturalArgs
             if (propertyNames) {
-                def ni = new NaturalId()
-                ni.mutable = (naturalArgs instanceof Map) && 
((Map)naturalArgs).mutable ?: false
+                NaturalId ni = new NaturalId()
+                ni.mutable = (naturalArgs instanceof Map) && ((Map) 
naturalArgs).mutable ?: false
                 if (propertyNames instanceof List) {
-                    ni.propertyNames = (List<String>)propertyNames
-                }
-                else {
+                    ni.propertyNames = (List<String>) propertyNames
+                } else {
                     ni.propertyNames = [propertyNames.toString()]
                 }
                 mapping.identity.natural = ni
             }
         }
         if (!args.composite && args) {
-            handleMethodMissing("id", [args] as Object[])
+            handlePropertyInternal("id", args, null)
         }
     }
 
     /**
-     * A closure used by methodMissing to create column definitions
+     * Typed property method for CompileStatic support.
      */
-    private Closure handleMethodMissing = { String name, Object args ->
-        if (args && ((args[0] instanceof Map) || (args[0] instanceof 
Closure))) {
-            Map namedArgs = args[0] instanceof Map ? args[0] : [:]
-
-            def newConfig = new PropertyConfig()
-            if(defaultConstraints != null && namedArgs.containsKey('shared')) {
-                PropertyConfig sharedConstraints = 
mapping.columns.get(namedArgs.shared)
-                if(sharedConstraints != null) {
-                    newConfig = (PropertyConfig)sharedConstraints.clone()
-                }
-            }
-            else if(mapping.columns.containsKey('*')) {
-                // apply global constraints constraints
-                PropertyConfig globalConstraints = mapping.columns.get('*')
-                if(globalConstraints != null) {
-                    newConfig = (PropertyConfig)globalConstraints.clone()
-                }
-            }
-
+    void property(Map args, String name) {
+        handlePropertyInternal(name, args, null)
+    }
 
-            PropertyConfig property = mapping.columns[name] ?: newConfig
-            property.name = namedArgs.name ?: property.name
-            property.generator = namedArgs.generator ?: property.generator
-            property.formula = namedArgs.formula ?: property.formula
-            property.accessType = namedArgs.accessType instanceof AccessType ? 
namedArgs.accessType : property.accessType
-            property.type = namedArgs.type ?: property.type
-            property.setLazy( namedArgs.lazy instanceof Boolean ? 
namedArgs.lazy : property.getLazy() )
-            property.insertable = namedArgs.insertable != null ? 
namedArgs.insertable : property.insertable
-            property.updatable = namedArgs.updateable != null ? 
namedArgs.updateable : property.updatable
-            property.updatable = namedArgs.updatable != null ? 
namedArgs.updatable : property.updatable
-            property.cascade = namedArgs.cascade ?: property.cascade
-            property.cascadeValidate = namedArgs.cascadeValidate != null ? 
namedArgs.cascadeValidate : property.cascadeValidate
-            property.sort = namedArgs.sort ?: property.sort
-            property.order = namedArgs.order ?: property.order
-            property.batchSize = namedArgs.batchSize instanceof Integer ? 
namedArgs.batchSize : property.batchSize
-            property.ignoreNotFound = namedArgs.ignoreNotFound instanceof 
Boolean ? namedArgs.ignoreNotFound : property.ignoreNotFound
-            property.typeParams = namedArgs.params ?: property.typeParams
-            property.setUnique( namedArgs.unique ? namedArgs.unique : 
property.unique)
-            property.nullable = namedArgs.nullable instanceof Boolean ? 
namedArgs.nullable : property.nullable
-            property.maxSize = namedArgs.maxSize instanceof Number ? 
namedArgs.maxSize : property.maxSize
-            property.minSize = namedArgs.minSize instanceof Number ? 
namedArgs.minSize : property.minSize
-            if(namedArgs.size instanceof IntRange) {
-                property.size = (IntRange)namedArgs.size
+    /**
+     * Internal logic for building property configurations.
+     */
+    protected void handlePropertyInternal(String name, Map namedArgs, Closure 
subClosure) {
+        PropertyConfig newConfig = new PropertyConfig()
+        if (defaultConstraints != null && namedArgs.containsKey('shared')) {
+            PropertyConfig sharedConstraints = 
mapping.columns.get(namedArgs.shared.toString())
+            if (sharedConstraints != null) {
+                newConfig = (PropertyConfig) sharedConstraints.clone()
             }
-            property.max = namedArgs.max instanceof Comparable ? namedArgs.max 
: property.max
-            property.min = namedArgs.min instanceof Comparable ? namedArgs.min 
: property.min
-            property.range = namedArgs.range instanceof ObjectRange ? 
namedArgs.range : null
-            property.inList = namedArgs.inList instanceof List ? 
namedArgs.inList : property.inList
-
-            // Need to guard around calling getScale() for multi-column 
properties (issue #1048)
-            if (namedArgs.scale instanceof Integer) {
-                property.scale = (Integer)namedArgs.scale
+        } else if (mapping.columns.containsKey('*')) {
+            PropertyConfig globalConstraints = mapping.columns.get('*')
+            if (globalConstraints != null) {
+                newConfig = (PropertyConfig) globalConstraints.clone()
             }
+        }
 
-            if (namedArgs.fetch) {
-                switch(namedArgs.fetch) {
-                    case ~/(join|JOIN)/:
-                        property.fetch = FetchMode.JOIN; break
-                    case ~/(select|SELECT)/:
-                        property.fetch = FetchMode.SELECT; break
-                    default:
-                        property.fetch = FetchMode.DEFAULT
-                }
-            }
+        PropertyConfig property = mapping.columns[name] ?: newConfig
+        property.name = namedArgs.name?.toString() ?: property.name
+        property.generator = namedArgs.generator?.toString() ?: 
property.generator
+        property.formula = namedArgs.formula?.toString() ?: property.formula
+        property.accessType = namedArgs.accessType instanceof AccessType ? 
(AccessType)namedArgs.accessType : property.accessType
+        property.type = namedArgs.type ?: property.type
+        property.setLazy(namedArgs.lazy instanceof Boolean ? 
(Boolean)namedArgs.lazy : property.getLazy())
+        property.insertable = namedArgs.insertable instanceof Boolean ? 
(Boolean)namedArgs.insertable : property.insertable
+        property.updatable = (namedArgs.updateable != null ? 
namedArgs.updateable : namedArgs.updatable) instanceof Boolean ? 
(Boolean)(namedArgs.updateable ?: namedArgs.updatable) : property.updatable
+        property.cascade = namedArgs.cascade?.toString() ?: property.cascade
+        property.cascadeValidate = namedArgs.cascadeValidate instanceof 
Boolean ? (Boolean)namedArgs.cascadeValidate : property.cascadeValidate
+        property.sort = namedArgs.sort?.toString() ?: property.sort
+        property.order = namedArgs.order?.toString() ?: property.order
+        property.batchSize = namedArgs.batchSize instanceof Integer ? 
(Integer)namedArgs.batchSize : property.batchSize
+        property.ignoreNotFound = namedArgs.ignoreNotFound instanceof Boolean 
? (Boolean)namedArgs.ignoreNotFound : property.ignoreNotFound
+        if (namedArgs.params instanceof Map) {
+            Properties typeProps = new Properties()
+            ((Map<Object, Object>)namedArgs.params).each { k, v -> 
typeProps.put(k, v) }
+            property.typeParams = typeProps
+        }
+
+        if (namedArgs.unique instanceof Boolean) 
property.setUnique((boolean)(Boolean)namedArgs.unique)
+        else if (namedArgs.unique instanceof String) 
property.setUnique((String)namedArgs.unique)
+        else if (namedArgs.unique instanceof List) 
property.setUnique((List<String>)namedArgs.unique)
+        property.nullable = namedArgs.nullable instanceof Boolean ? 
(Boolean)namedArgs.nullable : property.nullable
+        property.maxSize = namedArgs.maxSize instanceof Number ? 
(Number)namedArgs.maxSize : property.maxSize
+        property.minSize = namedArgs.minSize instanceof Number ? 
(Number)namedArgs.minSize : property.minSize
+
+        if (namedArgs.size instanceof IntRange) property.size = (IntRange) 
namedArgs.size
+        property.max = namedArgs.max instanceof Comparable ? (Comparable) 
namedArgs.max : property.max
+        property.min = namedArgs.min instanceof Comparable ? (Comparable) 
namedArgs.min : property.min
+        property.range = namedArgs.range instanceof ObjectRange ? 
(ObjectRange) namedArgs.range : null
+        property.inList = namedArgs.inList instanceof List ? (List) 
namedArgs.inList : property.inList
+
+        if (namedArgs.scale instanceof Integer) property.scale = (Integer) 
namedArgs.scale
+
+        if (namedArgs.fetch) {
+            String fetchStr = namedArgs.fetch.toString()
+            if (fetchStr.equalsIgnoreCase("join")) property.fetch = 
FetchMode.JOIN
+            else if (fetchStr.equalsIgnoreCase("select")) property.fetch = 
FetchMode.SELECT
+            else property.fetch = FetchMode.DEFAULT
+        }
 
-            // Deal with any column configuration for this property.
-            if (args[-1] instanceof Closure) {
-                // Multiple column definitions for this property.
-                Closure c = args[-1]
-                c.delegate = new PropertyDefinitionDelegate(property)
-                c.resolveStrategy = Closure.DELEGATE_ONLY
-                c.call()
+        if (subClosure != null) {
+            subClosure.delegate = new PropertyDefinitionDelegate(property)
+            subClosure.resolveStrategy = Closure.DELEGATE_ONLY
+            subClosure.call()
+        } else {
+            ColumnConfig cc = property.columns ? property.columns[0] : new 
ColumnConfig()
+            if (!property.columns) property.columns << cc
+
+            if (namedArgs["column"]) cc.name = namedArgs["column"].toString()
+            if (namedArgs["sqlType"]) cc.sqlType = 
namedArgs["sqlType"].toString()
+            if (namedArgs["enumType"]) cc.enumType = 
namedArgs["enumType"].toString()
+            if (namedArgs["index"]) cc.index = namedArgs["index"].toString()
+            if (namedArgs["unique"]) cc.unique = namedArgs["unique"]
+            if (namedArgs["read"]) cc.read = namedArgs["read"].toString()
+            if (namedArgs["write"]) cc.write = namedArgs["write"].toString()
+            if (namedArgs.defaultValue) cc.defaultValue = 
namedArgs.defaultValue.toString()
+            if (namedArgs.comment) cc.comment = namedArgs.comment.toString()
+            if (namedArgs["length"] instanceof Integer) cc.length = 
(Integer)namedArgs["length"]
+            if (namedArgs["precision"] instanceof Integer) cc.precision = 
(Integer)namedArgs["precision"]
+            if (namedArgs["scale"] instanceof Integer) cc.scale = 
(Integer)namedArgs["scale"]
+
+            if (namedArgs.joinTable instanceof String) {
+                property.joinTable((String)namedArgs.joinTable)
+            } else if (namedArgs.joinTable instanceof Map) {
+                property.joinTable((Map)namedArgs.joinTable)
             }
-            else {
-                // There is no sub-closure containing multiple column
-                // definitions, so pick up any column settings from
-                // the argument map.
-                ColumnConfig cc
-                if (property.columns) {
-                    cc = property.columns[0]
-                }
-                else {
-                    cc = new ColumnConfig()
-                    property.columns << cc
-                }
 
-                if (namedArgs["column"]) cc.name = namedArgs["column"]
-                if (namedArgs["sqlType"]) cc.sqlType = namedArgs["sqlType"]
-                if (namedArgs["enumType"]) cc.enumType = namedArgs["enumType"]
-                if (namedArgs["index"]) cc.index = namedArgs["index"]
-                if (namedArgs["unique"]) cc.unique = namedArgs["unique"]
-                if (namedArgs["read"]) cc.read = namedArgs["read"]
-                if (namedArgs["write"]) cc.write = namedArgs["write"]
-                if (namedArgs.defaultValue) cc.defaultValue = 
namedArgs.defaultValue
-                if (namedArgs.comment) cc.comment = namedArgs.comment
-                cc.length = namedArgs["length"] ?: cc.length
-                cc.precision = namedArgs["precision"] ?: cc.precision
-                cc.scale = namedArgs["scale"] ?: cc.scale
+            if (namedArgs.indexColumn instanceof Map) {
+                Map icArgs = (Map)namedArgs.indexColumn
+                PropertyConfig ic = new PropertyConfig()
+                ColumnConfig icc = new ColumnConfig()
+                if (icArgs.name) icc.name = icArgs.name.toString()
+                if (icArgs.type) icc.sqlType = icArgs.type.toString()
+                if (icArgs.length instanceof Integer) icc.length = 
(Integer)icArgs.length
+                ic.columns << icc
+                ic.type = icArgs.type
+                property.indexColumn = ic
             }
+        }
 
-            if (namedArgs.cache instanceof String) {
-                CacheConfig cc = new CacheConfig()
-                if (CacheConfig.USAGE_OPTIONS.contains(namedArgs.cache)) {
-                    cc.usage = namedArgs.cache
-                }
-                else {
-                    LOG.warn("ORM Mapping Invalid: Specified [usage] of 
[cache] with value [$args.usage] for association [$name] in class [$className] 
is not valid")
-                }
+        // Cache association handling
+        if (namedArgs.cache != null) {
+            CacheConfig cc = new CacheConfig()
+            if (namedArgs.cache instanceof String && 
CacheConfig.USAGE_OPTIONS.contains(namedArgs.cache)) {
+                cc.usage = namedArgs.cache.toString()
                 property.cache = cc
-            }
-            else if (namedArgs.cache == true) {
-                property.cache = new CacheConfig()
-            }
-            else if (namedArgs.cache instanceof Map) {
-                def cacheArgs = namedArgs.cache
-                CacheConfig cc = new CacheConfig()
-                if (CacheConfig.USAGE_OPTIONS.contains(cacheArgs.usage)) {
-                    cc.usage = cacheArgs.usage
-                }
-                else {
-                    LOG.warn("ORM Mapping Invalid: Specified [usage] of 
[cache] with value [$args.usage] for association [$name] in class [$className] 
is not valid")
-                }
-                if (CacheConfig.INCLUDE_OPTIONS.contains(cacheArgs.include)) {
-                    cc.include = cacheArgs.include
-                }
-                else {
-                    LOG.warn("ORM Mapping Invalid: Specified [include] of 
[cache] with value [$args.include] for association [$name] in class 
[$className] is not valid")
-                }
+            } else if (namedArgs.cache == true) {
+                property.cache = cc
+            } else if (namedArgs.cache instanceof Map) {
+                Map cacheArgs = (Map) namedArgs.cache
+                cc.usage = cacheArgs.usage?.toString()
+                cc.include = cacheArgs.include?.toString()
                 property.cache = cc
             }
-
-            if (namedArgs.indexColumn) {
-                def pc = new PropertyConfig()
-                property.indexColumn = pc
-                def cc = new ColumnConfig()
-                pc.columns << cc
-                def indexColArg = namedArgs.indexColumn
-                if (indexColArg instanceof Map) {
-                    if (indexColArg.type) {
-                        pc.type = indexColArg.remove('type')
-                    }
-                    bindArgumentsToColumnConfig(indexColArg, cc)
-                }
-                else {
-                    cc.name = indexColArg.toString()
-                }
-            }
-            if (namedArgs.joinTable) {
-                def join = new JoinTable()
-                def joinArgs = namedArgs.joinTable
-                if (joinArgs instanceof String) {
-                    join.name = joinArgs
-                }
-                else if (joinArgs instanceof Map) {
-                    if (joinArgs.schema) join.schema = 
joinArgs.remove('schema')
-                    if (joinArgs.catalog) join.catalog = 
joinArgs.remove('catalog')
-                    if (joinArgs.name) join.name = joinArgs.remove('name')
-                    if (joinArgs.key) {
-                        join.key = new 
ColumnConfig(name:joinArgs.remove('key'))
-                    }
-                    if (joinArgs.column) {
-                        ColumnConfig cc = new ColumnConfig(name: 
joinArgs.column)
-                        join.column = cc
-                        bindArgumentsToColumnConfig(joinArgs, cc)
-                    }
-                }
-                property.joinTable = join
-            }
-            else if (namedArgs.containsKey('joinTable') && namedArgs.joinTable 
== false) {
-                property.joinTable = null
-            }
-
-            mapping.columns[name] = property
         }
-    }
 
-    private bindArgumentsToColumnConfig(argMap, ColumnConfig cc) {
-        argMap.each { k, v ->
-            if (cc.metaClass.hasProperty(cc, k)) {
-                try {
-                    cc."$k" = v
-                }
-                catch (Exception e) {
-                    LOG.warn("Parameter [$k] cannot be used with [joinTable] 
argument")
-                }
-            }
-        }
+        mapping.columns[name] = property
     }
 
-    /**
-     * <p>Consumes the columns closure and populates the value into the 
Mapping objects columns property
-     *
-     * @param callable The closure containing the column definitions
-     */
-    @CompileStatic
-    void columns(Closure callable) {
+    void columns(@DelegatesTo(value = Object, strategy = 
Closure.DELEGATE_ONLY) Closure callable) {
         callable.resolveStrategy = Closure.DELEGATE_ONLY
         callable.delegate = new Object() {
             def invokeMethod(String methodName, Object args) {
-                handleMethodMissing.call(methodName, args)
+                Object[] argsArray = (Object[]) args
+                Map namedArgs = (argsArray.length > 0 && argsArray[0] 
instanceof Map) ? (Map)argsArray[0] : [:]
+                Closure sub = (argsArray.length > 0 && 
argsArray[argsArray.length - 1] instanceof Closure) ? 
(Closure)argsArray[argsArray.length - 1] : null
+                handlePropertyInternal(methodName, namedArgs, sub)
             }
         }
         callable.call()
     }
 
-    @CompileStatic
     void datasource(String name) {
         mapping.datasources = [name]
     }
 
-    @CompileStatic
     void datasources(List<String> names) {
         mapping.datasources = names
     }
 
-    @CompileStatic
     void comment(String comment) {
         mapping.comment = comment
     }
 
-    void methodMissing(String name, Object args) {
-        if(methodMissingIncludes != null && 
!methodMissingIncludes.contains(name)) {
-            return
-        }
-        else if(methodMissingExcludes.contains(name)) {
-            return
-        }
-
-        boolean hasArgs = args.asBoolean()
-        if ('user-type' == name && hasArgs && (args[0] instanceof Map)) {
-            hibernateCustomUserType(args[0])
-        }
-        else if('importFrom' == name && hasArgs && (args[0] instanceof Class)) 
{
-            // ignore, handled by constraints
-            List<Closure> constraintsToImports = 
ClassPropertyFetcher.getStaticPropertyValuesFromInheritanceHierarchy((Class)args[0],
 GormProperties.CONSTRAINTS, Closure)
-            if(constraintsToImports) {
-
-                List originalIncludes = this.methodMissingIncludes
-                List originalExludes = this.methodMissingExcludes
+    def methodMissing(String name, Object args) {
+        if (methodMissingIncludes != null && 
!methodMissingIncludes.contains(name)) return
+        if (methodMissingExcludes.contains(name)) return
+
+        Object[] argsArray = (Object[]) args
+        boolean hasArgs = argsArray.length > 0
+        if (name == 'user-type' && hasArgs && argsArray[0] instanceof Map) {
+            hibernateCustomUserType((Map) argsArray[0])
+        } else if (name == 'importFrom' && hasArgs && argsArray[0] instanceof 
Class) {
+            List<Closure> constraintsToImport = 
ClassPropertyFetcher.getStaticPropertyValuesFromInheritanceHierarchy(
+                (Class) argsArray[0], GormProperties.CONSTRAINTS, Closure)
+            if (constraintsToImport) {
+                List<String> originalIncludes = this.methodMissingIncludes
+                List<String> originalExcludes = this.methodMissingExcludes
                 try {
-                    if(args[-1] instanceof Map) {
-                        Map argMap = (Map) args[-1]
-                        def includes = argMap.get(INCLUDE_PARAM)
-                        def excludes = argMap.get(EXCLUDE_PARAM)
-                        if(includes instanceof List) {
-                            this.methodMissingIncludes = includes
-                        }
-                        if(excludes instanceof List) {
-                            this.methodMissingExcludes = excludes
-                        }
+                    Object lastArg = argsArray[argsArray.length - 1]
+                    if (lastArg instanceof Map) {
+                        Map argMap = (Map) lastArg
+                        Object includes = argMap.get(INCLUDE_PARAM)
+                        Object excludes = argMap.get(EXCLUDE_PARAM)
+                        if (includes instanceof List) 
this.methodMissingIncludes = (List<String>) includes
+                        if (excludes instanceof List) 
this.methodMissingExcludes = (List<String>) excludes
                     }
-
-                    for(Closure callable in constraintsToImports) {
-                        callable.setDelegate(this)
-                        callable.setResolveStrategy(Closure.DELEGATE_ONLY)
+                    for (Closure callable in constraintsToImport) {
+                        callable.delegate = this
+                        callable.resolveStrategy = Closure.DELEGATE_ONLY
                         callable.call()
                     }
                 } finally {
                     this.methodMissingIncludes = originalIncludes
-                    this.methodMissingExcludes = originalExludes
+                    this.methodMissingExcludes = originalExcludes
                 }
             }
-        }
-        else if (args && ((args[0] instanceof Map) || (args[0] instanceof 
Closure))) {
-            handleMethodMissing(name, args)
+        } else if (hasArgs && (argsArray[0] instanceof Map || argsArray[0] 
instanceof Closure)) {
+            Map namedArgs = argsArray[0] instanceof Map ? (Map)argsArray[0] : 
[:]
+            Closure sub = argsArray[argsArray.length - 1] instanceof Closure ? 
(Closure)argsArray[argsArray.length - 1] : null
+            handlePropertyInternal(name, namedArgs, sub)
         }
     }
-}
-
+}
\ No newline at end of file


Reply via email to