This is an automated email from the ASF dual-hosted git repository.
jamesfredley pushed a commit to branch fix/disable-groovy-indy-build
in repository https://gitbox.apache.org/repos/asf/grails-core.git
The following commit(s) were added to refs/heads/fix/disable-groovy-indy-build
by this push:
new b224f3320c fix: invoke Map constructors without Class.newInstance
under indy-off
b224f3320c is described below
commit b224f3320cad06460bfd6ea2c046f4b802bb829f
Author: James Fredley <[email protected]>
AuthorDate: Thu Aug 20 15:48:52 2026 -0400
fix: invoke Map constructors without Class.newInstance under indy-off
Class.newInstance(Map) is not selected under @CompileStatic when
invokedynamic is disabled. Use InvokerHelper.invokeConstructorOf with
an explicit Object[] so nested Map-constructor types still bind.
Also avoid `null as boolean` in the Map-constructor test fixture,
which Groovy 5 throws on without indy after unbindable properties
are filtered from constructor arguments.
Assisted-by: Sisyphus:grok-4.6
---
.../groovy/grails/databinding/SimpleDataBinder.groovy | 15 ++++++++++++++-
.../grails/web/databinding/GrailsWebDataBinderSpec.groovy | 3 ++-
.../grails/web/databinding/GrailsWebDataBinder.groovy | 3 ++-
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git
a/grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy
b/grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy
index c84fe8b77b..33846aee05 100755
---
a/grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy
+++
b/grails-databinding-core/src/main/groovy/grails/databinding/SimpleDataBinder.groovy
@@ -29,6 +29,7 @@ import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import groovy.xml.slurpersupport.GPathResult
import org.codehaus.groovy.reflection.CachedMethod
+import org.codehaus.groovy.runtime.InvokerHelper
import grails.databinding.converters.FormattedValueConverter
import grails.databinding.converters.ValueConverter
@@ -430,12 +431,24 @@ class SimpleDataBinder implements DataBinder {
try {
instance = referencedType.getDeclaredConstructor().newInstance()
} catch (NoSuchMethodException | IllegalAccessException ignored) {
- return referencedType.newInstance(values)
+ return newInstanceFromMapArguments(referencedType, values)
}
bind(instance, new SimpleMapDataBindingSource(values), listener)
instance
}
+ /**
+ * Invoke a {@code Map} constructor without calling Groovy's
+ * {@code Class.newInstance(Map)}. Under {@code @CompileStatic} with
+ * invokedynamic disabled that extension is not selected, so nested
+ * objects with only a Map constructor are left unbound.
+ */
+ protected Object newInstanceFromMapArguments(Class referencedType, Map
values) {
+ // Pass an Object[] so CompileStatic cannot treat the Map as named
+ // arguments or coerce it to a multi-arg constructor signature.
+ InvokerHelper.invokeConstructorOf(referencedType, new Object[] {
values })
+ }
+
@CompileStatic(TypeCheckingMode.SKIP)
protected initializeArray(obj, String propertyName, Class arrayType, int
index) {
Object[] array = obj[propertyName]
diff --git
a/grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy
b/grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy
index 43a1abcad9..c1b1df4b90 100644
---
a/grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy
+++
b/grails-test-suite-persistence/src/test/groovy/grails/web/databinding/GrailsWebDataBinderSpec.groovy
@@ -2163,7 +2163,8 @@ class SecureMapConstructorValue implements Validateable {
SecureMapConstructorValue(Map values) {
name = values.name
- admin = values.admin as boolean
+ // Groovy 5 without invokedynamic throws on `null as boolean`.
+ admin = Boolean.TRUE.equals(values.admin)
}
static constraints = {
diff --git
a/grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy
b/grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy
index 7110d200fc..61cf63b31d 100644
---
a/grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy
+++
b/grails-web-databinding/src/main/groovy/grails/web/databinding/GrailsWebDataBinder.groovy
@@ -641,7 +641,8 @@ class GrailsWebDataBinder extends SimpleDataBinder {
if (value instanceof Map) {
if (isBindAllIncludeList(includeList) ||
!DataBindingUtils.isDenyByDefaultEnabled()) {
- return
referencedType.newInstance(filterUnbindableMapConstructorArguments(referencedType,
(Map) value))
+ return newInstanceFromMapArguments(referencedType,
+
filterUnbindableMapConstructorArguments(referencedType, (Map) value))
}
if
(DataBindingUtils.isGeneratedBindingIncludeList(bindingIncludeList.get())) {
warnAboutMissingNoArgConstructor(referencedType)