Adding dynamic methods at runtime
Top: Plugin Dev Guide The Basics
Grails plugins allow you to register dynamic methods with any Grails managed or other class at runtime. New methods can only be added within a
doWithDynamicMethods closure of a plugin. After which no new methods can be added. This is to ensure thread safety when using dynamic methods.
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 MyPlugin { def doWithDynamicMethods = { applicationContext -> application.controllerClasses.each { controllerClass ->
controllerClass.metaClass.myNewMethod = {->
println "hello world"
}
}
}
}For other classes you can use the special "metaClass" property of each java.lang.Class:
To do this your plugin MUST depend on the core Grails plugin: static dependsOn = core:0.4 (+) as this plugin sets up the "metaClass" property on java.lang.Class
class MyPlugin { 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
The
doWithDynamicMethods closure gets passed the Spring ApplicationContext instance. This is useful as it allows you to interact with objects within it. For example if you where implementing a method to interact with Hibernate you could use the SessionFactory instance in combination with a HibernateTemplate:
To use the Hibernate plugin your plugin MUST depend on the hibernate Grails plugin: static dependsOn = hibernate:0.4 (+) as this plugin sets up the SessionFactory and Hibernate dependencies
import org.springframework.orm.hibernate3.HibernateTemplateclass MyHibernatePlugin { def doWithDynamicMethods = { applicationContext -> application.domainClasses.each { domainClass -> domainClass.metaClass.myNewPersistentMethod = { -> def sf = applicationContext.sessionFactory
def ht = new HibernateTemplate(sf) // do something with HibernateTemplate
}
}
}
}Also because of the autowiring and dependency injection capability of the Spring container you can implement more powerful dynamic constructors that use the application context to wire dependencies into your object at runtime:
class MyConstructorPlugin { def doWithDynamicMethods = { applicationContext -> application.domainClasses.each { domainClass -> domainClass.metaClass.ctor = {->
return applicationContext.getBean(domainClass.name)
}
}
}
} Top: Plugin Dev Guide