15.8 Adding Dynamic Methods at Runtime - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari
Version: 2.3.8
15.8 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
closure.For Grails-managed classes like controllers, tag libraries and so forth you can add methods, constructors etc. using the ExpandoMetaClass mechanism by accessing each controller's MetaClass:class ExamplePlugin { def doWithDynamicMethods = { applicationContext -> for (controllerClass in application.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 { def doWithDynamicMethods = { applicationContext -> 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 { def doWithDynamicMethods = { applicationContext -> for (domainClass in application.domainClasses) { domainClass.metaClass.static.load = { Long id-> def sf = applicationContext.sessionFactory def template = new HibernateTemplate(sf) template.load(delegate, id) } } } }
class MyConstructorPlugin { def doWithDynamicMethods = { applicationContext -> for (domainClass in application.domainClasses) { domainClass.metaClass.constructor = {-> return applicationContext.getBean(domainClass.name) } } } }