This is an automated email from the ASF dual-hosted git repository.

jamesfredley pushed a commit to branch feat/add-clearConstraintsMapCache-api
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit df0ba758597ef5e529ea85c324de7271de01994e
Author: James Fredley <[email protected]>
AuthorDate: Sun Jan 25 15:46:54 2026 -0500

    Add clearConstraintsMapCache() public API to Validateable trait
    
    Add a new static method to the Validateable trait that allows clearing
    the cached constraints map, forcing re-evaluation on next access.
    
    This is useful in testing scenarios where shared constraints may need
    to be re-evaluated after configuration changes, particularly during
    parallel test execution where constraints may be evaluated before
    doWithConfig() has registered shared constraints.
    
    The method enables proper test isolation by allowing tests to clear
    the constraint cache in setup/cleanup methods.
---
 .../commandobjects/CommandObjectNoDataSpec.groovy  | 21 ++++++++++++++++++++
 .../web/commandobjects/CommandObjectsSpec.groovy   | 23 ++++++++++++++++++++++
 .../groovy/grails/validation/Validateable.groovy   | 13 ++++++++++++
 .../validation/ValidateableTraitAdHocSpec.groovy   | 14 +++++++++++++
 .../grails/validation/ValidateableTraitSpec.groovy | 14 +++++++++++++
 5 files changed, 85 insertions(+)

diff --git 
a/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectNoDataSpec.groovy
 
b/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectNoDataSpec.groovy
index 09997cfad4..5e795a5081 100644
--- 
a/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectNoDataSpec.groovy
+++ 
b/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectNoDataSpec.groovy
@@ -20,6 +20,7 @@
 package org.grails.web.commandobjects
 
 import grails.testing.web.GrailsWebUnitTest
+import org.grails.validation.ConstraintEvalUtils
 import spock.lang.Specification
 
 class CommandObjectNoDataSpec extends Specification implements 
GrailsWebUnitTest {
@@ -30,6 +31,26 @@ class CommandObjectNoDataSpec extends Specification 
implements GrailsWebUnitTest
         }
     }}
 
+    /**
+     * Clear the static constraints cache for Artist class.
+     * This is necessary because the Validateable trait caches constraints in 
a static field,
+     * and in parallel test execution, the constraints may be evaluated before 
doWithConfig()
+     * has registered the shared constraint 'isProg'.
+     *
+     * Also clear ConstraintEvalUtils.defaultConstraintsMap which caches 
shared constraints
+     * globally. In parallel test execution, another test's config may have 
been cached,
+     * causing the 'isProg' shared constraint to not be found.
+     */
+    def setup() {
+        ConstraintEvalUtils.clearDefaultConstraints()
+        Artist.clearConstraintsMapCache()
+    }
+
+    def cleanup() {
+        ConstraintEvalUtils.clearDefaultConstraints()
+        Artist.clearConstraintsMapCache()
+    }
+
     void "test shared constraint"() {
         when:
         Artist artist = new Artist(name: "X")
diff --git 
a/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectsSpec.groovy
 
b/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectsSpec.groovy
index 12aeed8886..a4f19b5e15 100644
--- 
a/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectsSpec.groovy
+++ 
b/grails-test-suite-web/src/test/groovy/org/grails/web/commandobjects/CommandObjectsSpec.groovy
@@ -23,6 +23,7 @@ import grails.artefact.Artefact
 import grails.testing.gorm.DataTest
 import grails.testing.web.controllers.ControllerUnitTest
 import grails.validation.Validateable
+import org.grails.validation.ConstraintEvalUtils
 import spock.lang.Issue
 import spock.lang.Specification
 
@@ -38,6 +39,28 @@ class CommandObjectsSpec extends Specification implements 
ControllerUnitTest<Tes
         }
     }}
 
+    /**
+     * Clear the static constraints cache for classes that use shared 
constraints.
+     * This is necessary because the Validateable trait caches constraints in 
a static field,
+     * and in parallel test execution, the constraints may be evaluated before 
doWithConfig()
+     * has registered the shared constraint 'isProg'.
+     *
+     * Also clear ConstraintEvalUtils.defaultConstraintsMap which caches 
shared constraints
+     * globally. In parallel test execution, another test's config may have 
been cached,
+     * causing the 'isProg' shared constraint to not be found.
+     */
+    def setup() {
+        ConstraintEvalUtils.clearDefaultConstraints()
+        Artist.clearConstraintsMapCache()
+        ArtistSubclass.clearConstraintsMapCache()
+    }
+
+    def cleanup() {
+        ConstraintEvalUtils.clearDefaultConstraints()
+        Artist.clearConstraintsMapCache()
+        ArtistSubclass.clearConstraintsMapCache()
+    }
+
     void "Test command object with date binding"() {
         setup:
         def expectedCalendar = Calendar.instance
diff --git 
a/grails-validation/src/main/groovy/grails/validation/Validateable.groovy 
b/grails-validation/src/main/groovy/grails/validation/Validateable.groovy
index 2794dc2ad7..e69bc695ea 100644
--- a/grails-validation/src/main/groovy/grails/validation/Validateable.groovy
+++ b/grails-validation/src/main/groovy/grails/validation/Validateable.groovy
@@ -103,6 +103,19 @@ trait Validateable {
         return constraintsMapInternal
     }
 
+    /**
+     * Clears the cached constraints map, forcing re-evaluation on next access.
+     * This is useful in testing scenarios where shared constraints may need
+     * to be re-evaluated after configuration changes, particularly during
+     * parallel test execution.
+     *
+     * @since 7.1
+     */
+    @Generated
+    static void clearConstraintsMapCache() {
+        constraintsMapInternal = null
+    }
+
     /**
      * Validate the object
      *
diff --git 
a/grails-validation/src/test/groovy/grails/validation/ValidateableTraitAdHocSpec.groovy
 
b/grails-validation/src/test/groovy/grails/validation/ValidateableTraitAdHocSpec.groovy
index 248775600b..b8f2738cdc 100644
--- 
a/grails-validation/src/test/groovy/grails/validation/ValidateableTraitAdHocSpec.groovy
+++ 
b/grails-validation/src/test/groovy/grails/validation/ValidateableTraitAdHocSpec.groovy
@@ -27,6 +27,20 @@ import spock.lang.Specification
 
 class ValidateableTraitAdHocSpec extends Specification {
 
+    /**
+     * Clear the static constraints cache for classes that use shared 
constraints.
+     * This is necessary because the Validateable trait caches constraints in 
a static field,
+     * and in parallel test execution, the constraints may be evaluated before 
configuration
+     * has registered the shared constraints.
+     */
+    void setup() {
+        PersonAdHocSharedConstraintsValidateable.clearConstraintsMapCache()
+    }
+
+    void cleanup() {
+        PersonAdHocSharedConstraintsValidateable.clearConstraintsMapCache()
+    }
+
     void 'Test that pre-declared constraints can be used'() {
         given:
         def person = new PersonAdHocValidateable(name: nameValue, age: 
ageValue)
diff --git 
a/grails-validation/src/test/groovy/grails/validation/ValidateableTraitSpec.groovy
 
b/grails-validation/src/test/groovy/grails/validation/ValidateableTraitSpec.groovy
index 18f6ecbbb6..794f953c43 100644
--- 
a/grails-validation/src/test/groovy/grails/validation/ValidateableTraitSpec.groovy
+++ 
b/grails-validation/src/test/groovy/grails/validation/ValidateableTraitSpec.groovy
@@ -36,6 +36,20 @@ import java.lang.reflect.Method
  */
 class ValidateableTraitSpec extends Specification {
 
+    /**
+     * Clear the static constraints cache for classes that use shared 
constraints.
+     * This is necessary because the Validateable trait caches constraints in 
a static field,
+     * and in parallel test execution, the constraints may be evaluated before 
configuration
+     * has registered the shared constraints.
+     */
+    void setup() {
+        SharedConstraintsValidateable.clearConstraintsMapCache()
+    }
+
+    void cleanup() {
+        SharedConstraintsValidateable.clearConstraintsMapCache()
+    }
+
     void 'Test validate can be invoked in a unit test with no special 
configuration'() {
         when: 'an object is valid'
         def validateable = new MyValidateable(name: 'Kirk', age: 47, town: 
'STL')

Reply via email to