18.7 Adding Dynamic Methods at Runtime - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari
Version: 3.1.3
18.7 Adding Dynamic Methods at Runtime
The Basics
Grails plugins let you register dynamic methods with any Grails-managed or other class at runtime. This work is done in adoWithDynamicMethods
method.
Note that Grails 3.x features newer features such as traits that are usable from code compiled with CompileStatic
. It is recommended that dynamic behavior is only added for cases that are not possible with traits.
class ExamplePlugin extends Plugin { void doWithDynamicMethods() { for (controllerClass in grailsApplication.controllerClasses) { controllerClass.metaClass.myNewMethod = {-> println "hello world" } } } }
myNewMethod
to each controller. If you know beforehand the class you wish the add a method to you can simply reference its metaClass
property.For example we can add a new method swapCase
to java.lang.String
:class ExamplePlugin extends Plugin { @Override void doWithDynamicMethods() { String.metaClass.swapCase = {-> def sb = new StringBuilder() delegate.each { sb << (Character.isUpperCase(it as char) ? Character.toLowerCase(it as char) : Character.toUpperCase(it as char)) } sb.toString() } assert "UpAndDown" == "uPaNDdOWN".swapCase() } }
Interacting with the ApplicationContext
ThedoWithDynamicMethods
closure gets passed the Spring ApplicationContext
instance. This is useful as it lets you interact with objects within it. For example if you were implementing a method to interact with Hibernate you could use the SessionFactory
instance in combination with a HibernateTemplate
:import org.springframework.orm.hibernate3.HibernateTemplateclass ExampleHibernatePlugin extends Plugin{ void doWithDynamicMethods() { for (domainClass in grailsApplication.domainClasses) { domainClass.metaClass.static.load = { Long id-> def sf = applicationContext.sessionFactory def template = new HibernateTemplate(sf) template.load(delegate, id) } } } }
class MyConstructorPlugin { void doWithDynamicMethods() for (domainClass in grailsApplication.domainClasses) { domainClass.metaClass.constructor = {-> return applicationContext.getBean(domainClass.name) } } } }