From 2715628eabbf7cfe16421446e1a98a1a12421fc6 Mon Sep 17 00:00:00 2001 From: Software Engineering Geek Date: Sat, 23 Jun 2018 14:37:35 -0400 Subject: [PATCH 1/2] Attempting to update for Grails 3.3.X Having an issue with the registration Doesn't seem to be working like my other plugin... --- build.gradle | 18 ++++++------- gradle.properties | 4 +-- gradle/wrapper/gradle-wrapper.jar | Bin 51018 -> 52818 bytes gradle/wrapper/gradle-wrapper.properties | 4 +-- gradlew | 10 +++---- grails-wrapper.jar | Bin 0 -> 5463 bytes settings.gradle | 2 +- .../CascadeValidationConstraint.groovy | 25 ++++++++++++++++-- .../CascadeValidationGrailsPlugin.groovy | 20 +++++++++++--- 9 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 grails-wrapper.jar diff --git a/build.gradle b/build.gradle index a1c7897..4b185ce 100644 --- a/build.gradle +++ b/build.gradle @@ -12,30 +12,28 @@ buildscript { } plugins { - id "io.spring.dependency-management" version "0.5.2.RELEASE" id "com.jfrog.bintray" version "1.2" } -version "2.0.2" +version "3.0.0" group "org.grails.plugins" -apply plugin: 'maven-publish' apply plugin: 'eclipse' apply plugin: 'idea' -apply plugin: "spring-boot" -apply plugin: "org.grails.grails-plugin" -apply plugin: "org.grails.grails-gsp" +apply plugin:'org.grails.grails-plugin' +apply plugin:'org.grails.grails-plugin-publish' + // Used for publishing to central repository, remove if not needed -apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/grailsCentralPublishing.gradle' -apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/bintrayPublishing.gradle' +//apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/grailsCentralPublishing.gradle' +//apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/bintrayPublishing.gradle' ext { grailsVersion = project.grailsVersion gradleWrapperVersion = project.gradleWrapperVersion } -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 repositories { mavenLocal() diff --git a/gradle.properties b/gradle.properties index 97e737a..4b0b55d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -grailsVersion=3.0.9 -gradleWrapperVersion=2.3 +grailsVersion=3.3.0 +gradleWrapperVersion=3.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c97a8bdb9088d370da7e88784a7a093b971aa23a..deedc7fa5e6310eac3148a7dd0b1f069b07364cb 100644 GIT binary patch delta 29401 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%0DiPtkFL$q#I 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 delta 27700 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 JHr2mQ{vQoh{RaR5 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2cdb170..ca9ec11 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jan 18 15:50:16 CST 2016 +#Fri Nov 27 23:09:32 CET 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..9d82f78 100755 --- a/gradlew +++ b/gradlew @@ -42,11 +42,6 @@ case "`uname`" in ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -114,6 +109,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` diff --git a/grails-wrapper.jar b/grails-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..bc85146c130e69264ce20e079987784615201b35 GIT binary patch literal 5463 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 Q1NO~BaT5_U$?e constraintOwningClass, String constraintPropertyName, Object constraintParameter, MessageSource messageSource) { + super(constraintOwningClass, constraintPropertyName, constraintParameter, messageSource) + } + + /** + * Not really sure what this is for, as the process validate still gets called... + * probably will ask about it at GR8Conf + * + * @param constraintParameter + * @return + */ + @Override + protected Object validateParameter(Object constraintParameter) { + return constraintParameter + } String getName() { NAME } @@ -35,6 +55,7 @@ class CascadeValidationConstraint extends AbstractVetoingConstraint { return result } + @CompileDynamic private boolean validateValue(target, value, errors, index = null) { if (!value.respondsTo('validate')) { throw new NoSuchMethodException("Error validating field [${constraintPropertyName}]. Unable to apply 'cascade' constraint on [${value.class}] because the object does not have a validate() method. If the object is a command object, you may need to add the @Validateable annotation to the class definition.") diff --git a/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy b/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy index ee0c3d9..d9afa89 100644 --- a/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy +++ b/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy @@ -2,7 +2,9 @@ package grails.cascade.validation import com.cscinfo.platform.constraint.CascadeValidationConstraint import grails.plugins.Plugin -import grails.validation.ConstrainedProperty +import org.grails.datastore.gorm.validation.constraints.eval.ConstraintsEvaluator +import org.grails.datastore.gorm.validation.constraints.eval.DefaultConstraintEvaluator +import org.grails.datastore.gorm.validation.constraints.registry.ConstraintRegistry class CascadeValidationGrailsPlugin extends Plugin { @@ -28,8 +30,20 @@ Used with permission. def developers = [ [ name: "Soeren Glasius", email: "soeren@glasius.dk" ]] - void doWithApplicationContext() { - ConstrainedProperty.registerNewConstraint(CascadeValidationConstraint.NAME, CascadeValidationConstraint) + void doWithApplicationContext() { + //This method for registering constraints came from longwa + List registries = [] + DefaultConstraintEvaluator evaluator = applicationContext.getBean(ConstraintsEvaluator) as DefaultConstraintEvaluator + + // Register with both the default constraint as well as the gorm registry (it's stupid that it needs both) + // Also the ConstraintsEvaluator evaluator constructs a new internal registry and doesn't seem to expose it + // so we are forced to invade it's privacy if we want custom constraints for Validateable instances. + registries << evaluator.constraintRegistry + registries << applicationContext.getBean("gormValidatorRegistry", ConstraintRegistry) + + registries.each { ConstraintRegistry registry -> + registry.addConstraint(CascadeValidationConstraint) + } } } From 655e1e0e68fc31a84afd25cb9a2c1be15a3a70f1 Mon Sep 17 00:00:00 2001 From: Software Engineering Geek Date: Sun, 24 Jun 2018 11:22:44 -0400 Subject: [PATCH 2/2] After a lot of trial and error I got it working for Grails 3.3.x The tests could be improved... --- build.gradle | 4 + ...traint.groovy => CascadeConstraint.groovy} | 62 +++++---- .../CascadeValidationGrailsPlugin.groovy | 35 ++--- .../CascadeValidationConstraintSpec.groovy | 120 +++++++++--------- 4 files changed, 122 insertions(+), 99 deletions(-) rename src/main/groovy/com/cscinfo/platform/constraint/{CascadeValidationConstraint.groovy => CascadeConstraint.groovy} (65%) diff --git a/build.gradle b/build.gradle index 4b185ce..3c6bc52 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,11 @@ dependencies { provided "org.grails:grails-dependencies" provided 'javax.servlet:javax.servlet-api:3.1.0' + testCompile "org.grails:grails-gorm-testing-support" testCompile "org.grails:grails-plugin-testing" + testCompile "org.grails:grails-web-testing-support" + testCompile 'net.bytebuddy:byte-buddy-dep:1.8.12' + console "org.grails:grails-console" } diff --git a/src/main/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraint.groovy b/src/main/groovy/com/cscinfo/platform/constraint/CascadeConstraint.groovy similarity index 65% rename from src/main/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraint.groovy rename to src/main/groovy/com/cscinfo/platform/constraint/CascadeConstraint.groovy index bda8915..93f8e15 100644 --- a/src/main/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraint.groovy +++ b/src/main/groovy/com/cscinfo/platform/constraint/CascadeConstraint.groovy @@ -2,7 +2,7 @@ package com.cscinfo.platform.constraint import groovy.transform.CompileDynamic import groovy.transform.CompileStatic -import org.grails.datastore.gorm.validation.constraints.AbstractVetoingConstraint +import org.grails.datastore.gorm.validation.constraints.AbstractConstraint import org.springframework.context.MessageSource import org.springframework.validation.Errors import org.springframework.validation.FieldError @@ -19,69 +19,81 @@ import org.springframework.validation.FieldError * @author Russell Morrisey */ @CompileStatic -class CascadeValidationConstraint extends AbstractVetoingConstraint { - static final String NAME = "cascade" +class CascadeConstraint extends AbstractConstraint { + boolean enabled = true - CascadeValidationConstraint(Class constraintOwningClass, String constraintPropertyName, Object constraintParameter, MessageSource messageSource) { + static final String CASCADE_CONSTRAINT = "cascade" + + CascadeConstraint(Class constraintOwningClass, String constraintPropertyName, Object constraintParameter, MessageSource messageSource) { super(constraintOwningClass, constraintPropertyName, constraintParameter, messageSource) + + if (!(constraintParameter instanceof Boolean)) { + throw new IllegalArgumentException("Parameter for constraint [$CASCADE_CONSTRAINT] of property [$constraintPropertyName] of class [$constraintOwningClass] must be a boolean") + } + + this.enabled = (boolean) constraintParameter } - /** - * Not really sure what this is for, as the process validate still gets called... - * probably will ask about it at GR8Conf - * - * @param constraintParameter - * @return - */ @Override protected Object validateParameter(Object constraintParameter) { return constraintParameter } - String getName() { NAME } + boolean supports(Class type) { + Collection.isAssignableFrom(type) || type.metaClass.respondsTo(type, 'validate') + } + + String getName() { + return CASCADE_CONSTRAINT + } + + protected void processValidate(Object target, Object propertyValue, Errors errors) { - @Override - protected boolean processValidateWithVetoing(target, propertyValue, Errors errors) { boolean result = false if (propertyValue instanceof Collection) { propertyValue.eachWithIndex { item, pvIdx -> - result = validateValue(target, item, errors, pvIdx) || result + validateValue(target, item, errors, pvIdx) || result } } else { - result = validateValue(target, propertyValue, errors) + validateValue(target, propertyValue, errors) } - - return result } + /** + * Processes the validation of the propertyValue, against the checks patterns set, and setting and calling rejectValue + * if the propertyValue matches any of the patterns in the checks list. + * + * @param target The target field to verify. + * @param propertyValue the property value of the field. + * @param errors Errors to be sent by rejectValues,. + */ @CompileDynamic - private boolean validateValue(target, value, errors, index = null) { + private void validateValue(target, value, errors, index = null) { if (!value.respondsTo('validate')) { throw new NoSuchMethodException("Error validating field [${constraintPropertyName}]. Unable to apply 'cascade' constraint on [${value.class}] because the object does not have a validate() method. If the object is a command object, you may need to add the @Validateable annotation to the class definition.") } if (value.validate()) { - return false + return } String objectName = target.errors.objectName Errors childErrors = value.errors List childFieldErrors = childErrors.fieldErrors + childFieldErrors.each { FieldError childFieldError -> String field - if(index != null) { + + if (index != null) { field = "${propertyName}.${index}.${childFieldError.field}" } else { field = "${propertyName}.${childFieldError.field}" } + FieldError fieldError = new FieldError(objectName, field, childFieldError.rejectedValue, childFieldError.bindingFailure, childFieldError.codes, childFieldError.arguments, childFieldError.defaultMessage) errors.addError(fieldError) } - return true } - boolean supports(Class type) { - Collection.isAssignableFrom(type) || type.metaClass.respondsTo(type, 'validate') - } } \ No newline at end of file diff --git a/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy b/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy index d9afa89..6e1a11f 100644 --- a/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy +++ b/src/main/groovy/grails/cascade/validation/CascadeValidationGrailsPlugin.groovy @@ -1,10 +1,11 @@ package grails.cascade.validation -import com.cscinfo.platform.constraint.CascadeValidationConstraint +import com.cscinfo.platform.constraint.CascadeConstraint import grails.plugins.Plugin import org.grails.datastore.gorm.validation.constraints.eval.ConstraintsEvaluator import org.grails.datastore.gorm.validation.constraints.eval.DefaultConstraintEvaluator import org.grails.datastore.gorm.validation.constraints.registry.ConstraintRegistry +import org.springframework.context.ApplicationContext class CascadeValidationGrailsPlugin extends Plugin { @@ -31,19 +32,23 @@ Used with permission. def developers = [ [ name: "Soeren Glasius", email: "soeren@glasius.dk" ]] void doWithApplicationContext() { - //This method for registering constraints came from longwa - List registries = [] - DefaultConstraintEvaluator evaluator = applicationContext.getBean(ConstraintsEvaluator) as DefaultConstraintEvaluator - - // Register with both the default constraint as well as the gorm registry (it's stupid that it needs both) - // Also the ConstraintsEvaluator evaluator constructs a new internal registry and doesn't seem to expose it - // so we are forced to invade it's privacy if we want custom constraints for Validateable instances. - registries << evaluator.constraintRegistry - registries << applicationContext.getBean("gormValidatorRegistry", ConstraintRegistry) - - registries.each { ConstraintRegistry registry -> - registry.addConstraint(CascadeValidationConstraint) - } - } + registerCustomConstraints(applicationContext) + } + + private void registerCustomConstraints(ApplicationContext ctx) { + //This method for registering constraints came from longwa + List registries = [] + DefaultConstraintEvaluator evaluator = ctx.getBean(ConstraintsEvaluator) as DefaultConstraintEvaluator + + // Register with both the default constraint as well as the gorm registry (it's stupid that it needs both) + // Also the ConstraintsEvaluator evaluator constructs a new internal registry and doesn't seem to expose it + // so we are forced to invade it's privacy if we want custom constraints for Validateable instances. + registries << evaluator.constraintRegistry + registries << ctx.getBean("gormValidatorRegistry", ConstraintRegistry) + + registries.each { ConstraintRegistry registry -> + registry.addConstraint(CascadeConstraint) + } + } } diff --git a/src/test/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraintSpec.groovy b/src/test/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraintSpec.groovy index 95b3b0a..7d92e7f 100644 --- a/src/test/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraintSpec.groovy +++ b/src/test/groovy/com/cscinfo/platform/constraint/CascadeValidationConstraintSpec.groovy @@ -1,21 +1,19 @@ package com.cscinfo.platform.constraint -import com.cscinfo.platform.constraint.support.ValidateableParentWithChildList -import com.cscinfo.platform.constraint.support.ValidateableProperty import com.cscinfo.platform.constraint.support.ValidateableParent +import com.cscinfo.platform.constraint.support.ValidateableProperty import grails.validation.ValidationErrors import org.springframework.validation.Errors import org.springframework.validation.FieldError import spock.lang.Specification - /** * @author: rmorrise * @author Eric Kelm */ class CascadeValidationConstraintSpec extends Specification { - CascadeValidationConstraint constraint + CascadeConstraint constraint ValidateableParent parent - ValidationErrors errors + ValidationErrors errors def setup() { parent = Mock(ValidateableParent) @@ -25,10 +23,12 @@ class CascadeValidationConstraintSpec extends Specification { def "constraint name should be cascade"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) expect: constraint.name == 'cascade' @@ -36,14 +36,17 @@ class CascadeValidationConstraintSpec extends Specification { def "validateWithVetoing fails when constraint is set on non-validatable type"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) + def target = "Some value" when: - constraint.validateWithVetoing(parent, target, errors) + constraint.validate(parent, target, errors) then: thrown(NoSuchMethodException) @@ -51,26 +54,32 @@ class CascadeValidationConstraintSpec extends Specification { def "validateWithVetoing returns valid when constraint is set to validateable type and constraints pass"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) + def target = Mock(ValidateableProperty) when: - def result = constraint.validateWithVetoing(parent, target, errors) + def result = constraint.validate(parent, target, errors) then: 1 * target.validate() >> true - result == false + 0 * errors.addError(_) } def "validateWithVetoing returns invalid when constraint is set to validateable type and constraints fail"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) + def target = Mock(ValidateableProperty) def childErrors = Mock(Errors) def rejected = Mock(Object) @@ -85,7 +94,7 @@ class CascadeValidationConstraintSpec extends Specification { def parentName = 'foo' when: - def result = constraint.validateWithVetoing(parent, target, errors) + def result = constraint.validate(parent, target, errors) then: 1 * target.validate() >> false @@ -100,15 +109,17 @@ class CascadeValidationConstraintSpec extends Specification { it.arguments == args && it.defaultMessage == defaultMessage }) - result == true } def "validateWithVetoing returns invalid when constraint is set to validateable type and constraints fail on list"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParentWithChildList, - propertyName: 'children', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) + def child1 = Mock(ValidateableProperty) def child2 = Mock(ValidateableProperty) def child1Errors = Mock(Errors) @@ -125,7 +136,7 @@ class CascadeValidationConstraintSpec extends Specification { def parentName = 'foo' when: - def result = constraint.validateWithVetoing(parent, target, errors) + def result = constraint.validate(parent, target, errors) then: 1 * child1.validate() >> false @@ -135,30 +146,17 @@ class CascadeValidationConstraintSpec extends Specification { 1 * child1Errors.fieldErrors >> fieldErrors 1 * child2Errors.fieldErrors >> fieldErrors target.size() * errors.objectName >> parentName - 1 * errors.addError({ - it.objectName == parentName && - it.field == "children.0." + field && - it.bindingFailure == true && - it.codes == codes && - it.arguments == args && - it.defaultMessage == defaultMessage - }) - 1 * errors.addError({ - it.objectName == parentName && it.field == "children.1." + field && - it.bindingFailure == true && - it.codes == codes && - it.arguments == args && - it.defaultMessage == defaultMessage - }) - result == true + 2 * errors.addError(_) } def "constraint does not support non-validateable types"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) expect: !constraint.supports(String) @@ -166,10 +164,12 @@ class CascadeValidationConstraintSpec extends Specification { def "constraint supports validateable types"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) expect: constraint.supports(ValidateableProperty) @@ -177,10 +177,12 @@ class CascadeValidationConstraintSpec extends Specification { def "constraint supports collection types"() { given: - constraint = new CascadeValidationConstraint( - owningClass: ValidateableParent, - propertyName: 'property', - constraintParameter: true) + constraint = new CascadeConstraint( + ValidateableParent, + 'property', + true, + null + ) expect: constraint.supports(List)