“Overloading” standard GORM CRUD methods

纵然是瞬间 提交于 2019-12-10 11:23:07

问题


Wanna do the following:

BootStrap {
  def init = {servletContext ->
  ........
  MyDomainClass.metaClass.save = {-> 
     delegate.extraSave()
     //////// how to call original save() here?
  }

}
.........
}

P.S. MyDomainClass#extraSave is defined as public void extraSave(){.....}


回答1:


First of all, Bootstrap.groovy may not be the best place to do this kind of metaprogramming. The problem with this approach is that the changes to the classes will be applied when the application starts, but you may lose these changes when the application is reloaded. Obviously this is only an issue during development, and not an issue at all if you don't mind restarting the server every time you make a change, but I'll bet this would quickly become a major annoyance. In order to have the changes applied when app is reloaded as well, you should move the metaprogramming into a plugin, where you can hook into the onChange application lifecycle event.

So the steps are:

  • Create a plugin
  • Do the metaprogramming in the doWithDynamicMethods and onChange closures of the plugin descriptor

Here's a complete example where I "override" the chain() method on all the controller classes. The code to do likewise for the save() method of domain classes should only require some obvious replacements, e.g. use application.domainClasses instead of application.controllerClasses

def doWithDynamicMethods = {ctx ->

    application.controllerClasses.each {controller ->
        replaceChain(controller)
    }
}

def onChange = {event ->
    if (application.isArtefactOfType(ControllerArtefactHandler.TYPE, event.source)) {
        def clz = application.getControllerClass(event.source?.name)
        replaceChain(clz)
    }
}

private replaceChain(controllerClass) {

    // Save a  reference to the grails chain() method
    def grailsChain = controllerClass.metaClass.pickMethod("chain", [Map] as Class[])

    controllerClass.metaClass.chain = {Map params ->

        println "My code to execute before chain goes here"

        // Invoke the grails chain() method
        grailsChain.invoke(delegate, [params] as Object[])

        println "My code to execute after chain goes here"
    }
}



回答2:


why not leveraging the GORM events for this purpose? In the Domain class:

def extraSave() {
    // ...
}

def beforeInsert = {
    extraSave()
}

def beforeUpdate = {
    extraSave()
}

IMHO this a cleaner approach. Documentation can be found here




回答3:


Not sure if the following works, but this might be a solution:

MyDomainClass.metaClass.origSave = MyDomainClass.metaClass.save
MyDomainClass.metaClass.save = {-> 
   delegate.extraSave()
   delegate.origSave()
}

Please give me feedbeck if the above worked...



来源:https://stackoverflow.com/questions/1664096/overloading-standard-gorm-crud-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!