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')
