Skip to content

Instantly share code, notes, and snippets.

@MarkMenard
Created October 11, 2010 19:18
Show Gist options
  • Save MarkMenard/621058 to your computer and use it in GitHub Desktop.
Save MarkMenard/621058 to your computer and use it in GitHub Desktop.
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