Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

custom Grails validation

Normally for a Grails domain or command class, you declare your constraints and the framework adds a validate() method that checks whether each of these constraints is valid for the current instance e.g.

class Adult {

  String name
  Integer age

  void preValidate() { 
    // Implementation omitted
  }

  static constraints = {
    name(blank: false)
    age(min: 18)
  }
}

def p = new Person(name: 'bob', age: 21)
p.validate()

In my case I want to make sure that preValidate is always executed before the class is validated. I could achieve this by adding a method

def customValidate() {
  preValidate()
  validate()
}

But then everyone who uses this class needs to remember to call customValidate instead of validate. I can't do this either

def validate() {
  preValidate()
  super.validate()
}

Because validate is not a method of the parent class (it's added by metaprogramming). Is there another way to achieve my goal?

like image 605
Dónal Avatar asked Apr 10 '11 17:04

Dónal


2 Answers

You should be able to accomplish this by using your own version of validate on the metaclass, when your domain/command class has a preValidate() method. Something similar to the below code in your BootStrap.groovy could work for you:

class BootStrap {

    def grailsApplication   // Set via dependency injection

    def init = { servletContext ->

        for (artefactClass in grailsApplication.allArtefacts) {
            def origValidate = artefactClass.metaClass.getMetaMethod('validate', [] as Class[])
            if (!origValidate) {
                continue
            }

            def preValidateMethod = artefactClass.metaClass.getMetaMethod('preValidate', [] as Class[])
            if (!preValidateMethod) {
                continue
            }

            artefactClass.metaClass.validate = {
                preValidateMethod.invoke(delegate)
                origValidate.invoke(delegate)
            }
        }
    }

    def destroy = {
    }
}
like image 149
Derek Slife Avatar answered Sep 24 '22 02:09

Derek Slife


You may be able to accomplish your goal using the beforeValidate() event. It's described in the 1.3.6 Release Notes.

like image 25
Jim Norman Avatar answered Sep 26 '22 02:09

Jim Norman