Created
October 11, 2010 19:18
-
-
Save MarkMenard/621058 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.springframework.beans.BeanUtils | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
@Category(Object) | |
class PropertyUtils { | |
def getPropertyValue (Class clazz, String name, Object ob) { | |
Method getter = BeanUtils.findDeclaredMethod(clazz, getGetterName(name), null) | |
try { | |
if (getter != null) { | |
return getter.invoke(ob) | |
} | |
Field f = clazz.getDeclaredField(name) | |
if (f != null) { | |
return f.get(ob) | |
} | |
} | |
catch (Exception ignored) { | |
// ignored.printStackTrace() | |
} | |
return null | |
} | |
/** | |
* <p>Get a static property value, which has a public static getter or is just a public static field.</p> | |
* | |
* @param clazz The class to check for static property | |
* @param name The property name | |
* @return The value if there is one, or null if unset OR there is no such property | |
*/ | |
def getStaticPropertyValue (Class clazz, String name) { | |
Method getter = BeanUtils.findDeclaredMethod(clazz, getGetterName(name), null) | |
try { | |
if (getter != null) { | |
return getter.invoke(null) | |
} | |
Field f = clazz.getDeclaredField(name) | |
if (f != null) { | |
return f.get(null) | |
} | |
} | |
catch (Exception ignored) { | |
// ignored.printStackTrace() | |
} | |
return null | |
} | |
public String getGetterName (String propertyName) { | |
return "get${Character.toUpperCase(propertyName.charAt(0))}${propertyName.substring(1)}" | |
} | |
} | |
@Category(Object) | |
class ClassUtils { | |
List getSuperClassChain (Class theClass) { | |
LinkedList classChain = new LinkedList () | |
Class clazz = theClass | |
while (clazz != Object) { | |
classChain.addFirst( clazz) | |
clazz = clazz.getSuperclass() | |
} | |
return classChain | |
} | |
} | |
@Category(Object) | |
class Validations { | |
def validatesPresenceOf (property, options = [:]) { | |
if (!this."${property}" || this."${property}".length() == 0) { | |
errors.addPropertyError(property, options['message'] ?: 'Required') | |
} | |
} | |
} | |
class ValidationErrors { | |
def propertyErrors = [:] | |
def baseErrors = [] | |
def addBaseError (message) { | |
baseErrors << message | |
} | |
def addToBase (message) { | |
addBaseError(message) | |
} | |
def addPropertyError (property, message) { | |
initializePropertyErrors(property) | |
propertyErrors[property] << message | |
} | |
def getErrorsOn (property) { | |
propertyErrors(property) | |
} | |
def initializePropertyErrors (property) { | |
if (propertyErrors[property] == null) { | |
propertyErrors[property] = [] | |
} | |
} | |
def hasErrors () { | |
hasBaseErrors() || hasPropertyErrors() | |
} | |
def hasBaseErrors () { | |
baseErrors.size > 0 | |
} | |
def hasPropertyErrors () { | |
getPropertyMessages().size() > 0 | |
} | |
def reset () { | |
propertyErrors = [:] | |
baseErrors = [] | |
} | |
def getFullMessages () { | |
def result = [] | |
result << getBaseMessages() | |
result << getPropertyMessages() | |
result.flatten() | |
} | |
def getBaseMessages () { | |
baseErrors | |
} | |
def getPropertyMessages () { | |
propertyErrors.keySet().collect { key -> propertyErrors[key].collect { message -> "${key} ${message}"} }.flatten() | |
} | |
} | |
@Category(Object) | |
@Mixin(PropertyUtils) | |
@Mixin(ClassUtils) | |
@Mixin(Validations) | |
class Base { | |
def isValid () { | |
initializeErrors() | |
doValidations() | |
errors.hasErrors() | |
} | |
def initializeErrors () { | |
def errors = new ValidationErrors () | |
def emc = new ExpandoMetaClass( this.class, false ) | |
emc.getErrors = { -> errors } | |
emc.initialize() | |
this.metaClass = emc | |
} | |
def doValidations () { | |
doValidation('validates') | |
if (isPersisted()) { | |
doValidation('validatesOnUpdate') | |
} else { | |
doValidation('validatesOnCreate') | |
} | |
} | |
def doValidation (validationClosureName) { | |
println "Performing ${validationClosureName} validation." | |
getSuperClassChain(this.class).collect { klass -> | |
getStaticPropertyValue(klass, validationClosureName) | |
}.findAll { | |
it != null | |
}.each { | |
it.setDelegate(this) | |
it.call() | |
} | |
} | |
def isPersisted () { | |
this.id != null | |
} | |
} | |
@Mixin(Base) | |
class Person { | |
def id | |
def name | |
static validates = { bean -> | |
validatesPresenceOf('name') | |
errors.addToBase("FRACK!") | |
} | |
} | |
class Employee extends Person { | |
def position | |
static validates = { bean -> | |
validatesPresenceOf('position') | |
} | |
} | |
e = new Employee () | |
e.isValid() | |
println e.errors.getFullMessages() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment