12.8 Adding Dynamic Methods at Runtime - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: null
12.8 Adding Dynamic Methods at Runtime
The Basics
Introducción
Grails plugins let you register dynamic methods with any Grails-managed or other class at runtime. This work is done in a
Los plugins de grails permiten registrar dinámicamente métodos en clases gestionadas por Grails o cualquier otra clase en tiempo de ejecución. Esto se consigue a través de la closure doWithDynamicMethods closure.
doWithDynamicMethods
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:
Para las clases gestionadas por grails, como los controladores, librerías de tags y otras, es posible añadir métodos, constructures etc. usando el mecanismo ExpandoMetaClass accediendo al MetaClass de cada controlador.class ExamplePlugin {
def doWithDynamicMethods = { applicationContext ->
for (controllerClass in application.controllerClasses) {
controllerClass.metaClass.myNewMethod = {-> println "hello world" }
}
}
}
In this case we use the implicit application object to get a reference to all of the controller classes' MetaClass instances and add a new method called
En este caso, usamos el objeto implicito "application" para obtener una referencia a al atributo "metaClass" de las clases controladoras, y añadir un nuevo método llamado myNewMethod to each controller. If you know beforehand the class you wish the add a method to you can simply reference its metaClass property.
myNewMethod a cada controlador. Conociendo de antemano la clase a la que se desea añadir el método, esto se puede hacer de manera más sencilla accediendo directamente su atributo metaClass
For example we can add a new method
Por ejemplo, podríamos añadir un nuevo método swapCase to java.lang.String:
swapCase a 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
Interaccionando con el ApplicationContext
The
La closure doWithDynamicMethods 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:
doWithDynamicMethods recibe como parámetro la intancia del ApplicationContext de Spring. Esto es muy útil porque permite interactuar con los objetos que contiene. Por ejemplo, si se está implementando un método para interacturar con Hibernate se podría usar la instancia del SessionFactory en combinación con un HibernateTemplateimport 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) } } } }
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:
También es importante destacar que gracias a las capacidades de autowiring e inyección de dependencias de Spring, es posible implementar potentes constructores usando el application context para enlazar dependencias en tus objetos en tiempo de ejecución.class MyConstructorPlugin { def doWithDynamicMethods = { applicationContext ->
for (domainClass in application.domainClasses) {
domainClass.metaClass.constructor = {->
return applicationContext.getBean(domainClass.name)
}
}
}
}
Here we actually replace the default constructor with one that looks up prototyped Spring beans instead!
En el ejemplo de hecho se está remplazando el constructor por defecto por otro que devuelve un objeto definido en Spring tipo "prototype" en lugar de crear una clase nueva.

