Skip to content

Upgrading Cascade constraint to work with Grails 3.3 #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -60,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"
}
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
grailsVersion=3.0.9
gradleWrapperVersion=2.3
grailsVersion=3.3.0
gradleWrapperVersion=3.5
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
10 changes: 3 additions & 7 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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

Expand Down Expand Up @@ -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`
Expand Down
Binary file added grails-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = "cascade-validation"
rootProject.name = "grails-cascade-validation"
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.cscinfo.platform.constraint

import grails.validation.AbstractVetoingConstraint
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import org.grails.datastore.gorm.validation.constraints.AbstractConstraint
import org.springframework.context.MessageSource
import org.springframework.validation.Errors
import org.springframework.validation.FieldError

Expand All @@ -15,52 +18,82 @@ import org.springframework.validation.FieldError
* @author Eric Kelm
* @author Russell Morrisey
*/
class CascadeValidationConstraint extends AbstractVetoingConstraint {
public static final String NAME = "cascade"
@CompileStatic
class CascadeConstraint extends AbstractConstraint {
boolean enabled = true

String getName() { NAME }
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
}

@Override
protected boolean processValidateWithVetoing(target, propertyValue, Errors errors) {
protected Object validateParameter(Object constraintParameter) {
return constraintParameter
}

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

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
}

private boolean validateValue(target, value, errors, index = null) {
/**
* 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 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<FieldError> 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')
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package grails.cascade.validation

import com.cscinfo.platform.constraint.CascadeValidationConstraint
import com.cscinfo.platform.constraint.CascadeConstraint
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
import org.springframework.context.ApplicationContext

class CascadeValidationGrailsPlugin extends Plugin {

Expand All @@ -28,8 +31,24 @@ Used with permission.

def developers = [ [ name: "Soeren Glasius", email: "[email protected]" ]]

void doWithApplicationContext() {
ConstrainedProperty.registerNewConstraint(CascadeValidationConstraint.NAME, CascadeValidationConstraint)
}
void doWithApplicationContext() {
registerCustomConstraints(applicationContext)
}

private void registerCustomConstraints(ApplicationContext ctx) {
//This method for registering constraints came from longwa
List<ConstraintRegistry> 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)
}
}

}
Loading