Skip to content

Instantly share code, notes, and snippets.

@joseanpg
Last active December 11, 2015 19:28
Show Gist options
  • Save joseanpg/4648339 to your computer and use it in GitHub Desktop.
Save joseanpg/4648339 to your computer and use it in GitHub Desktop.
/*
http://groovy.codehaus.org/Using+the+Delegating+Meta+Class
Each groovy object has a metaClass that is used to manage the dynamic nature of the language.
This class intercepts calls to groovy objects to ensure that the appropriate grooviness can be added.
For example, when an object is constructed, the MetaClass's invokeConstructor()is called.
One feature of the invokeConstructor allows us to create groovy objects using a map argument
to set the properties of the object (new X([prop1: value1, prop2: value2])).
*/
//POGOs
class Z {}
println Z.metaClass.class //class org.codehaus.groovy.runtime.HandleMetaClass
println Z.metaClass //org.codehaus.groovy.runtime.HandleMetaClass@10b841[groovy.lang.MetaClassImpl@10b841[class Z]]
/*
https://github.com/groovy/groovy-core/blob/master/src/main/org/codehaus/groovy/runtime/HandleMetaClass.java
https://github.com/groovy/groovy-core/blob/master/src/main/groovy/lang/DelegatingMetaClass.java
https://github.com/groovy/groovy-core/blob/master/src/main/groovy/lang/MetaClassImpl.java
org.codehaus.groovy.runtime.HandleMetaClass groovy.lang.DelegatingMetaClass
*/
a = new Z()
println a.metaClass.class //class org.codehaus.groovy.runtime.HandleMetaClass
println a.metaClass //org.codehaus.groovy.runtime.HandleMetaClass@10b841[groovy.lang.MetaClassImpl@10b841[class Z]]
//
// Z ------- metaClass --------> HandleMetaClass@10b841 ----- delegate -----> MetaClassImpl@10b841
// ^
// |
// a ------- metaClass --------------------+
a.x = 5
a.@metaClass[[HandleMetaClass]].@setProperty("x",5);
a.@metaClass[[HandleMetaClass]].@delegate[[MetaClassImpl]].@setProperty("x",5)
a.[[Z]]setProperty("x",5)
groovy.lang.MissingPropertyException: No such property: x for class: Z
//----
def a = new Z()
println a.metaClass.class // Sigue siendo class org.codehaus.groovy.runtime.HandleMetaClass
println a.metaClass // org.codehaus.groovy.runtime.HandleMetaClass@10b841[groovy.lang.MetaClassImpl@10b841[class Z]]
a.metaClass.x = 5
println a.x // 5
println a.metaClass.class // Sigue siendo class org.codehaus.groovy.runtime.HandleMetaClass
// pero el objeto ha cambiado
println a.metaClass // org.codehaus.groovy.runtime.HandleMetaClass@1b8cdd5[groovy.lang.ExpandoMetaClass@1b8cdd5[class Z]]
//
// Z ------- metaClass --------> HandleMetaClass@10b841 ---- delegate ----> MetaClassImpl@10b841
//
//
// a ------- metaClass --------> HandleMetaClass@1b8cdd5 --- delegate ----->ExpandoMetaClass@1b8cdd5
Z.metaClass.z = 5
println Z.metaClass.class //class groovy.lang.ExpandoMetaClass
println Z.metaClass //groovy.lang.ExpandoMetaClass@39a867[class Z]
def b = new Z();
println b.z
println b.metaClass.class // class org.codehaus.groovy.runtime.HandleMetaClass
println b.metaClass // org.codehaus.groovy.runtime.HandleMetaClass@39a867[groovy.lang.ExpandoMetaClass@39a867[class Z]]
//
// Z ------- metaClass --------> ExpandoMetaClass@39a867 <--------------+
// |
// |
// b ------- metaClass --------> HandleMetaClass@39a867 --- delegate ---+
b.metaClass.y = 7
println b.y
println b.metaClass.class // class org.codehaus.groovy.runtime.HandleMetaClass
println b.metaClass // org.codehaus.groovy.runtime.HandleMetaClass@d88aa2[groovy.lang.ExpandoMetaClass@d88aa2[class Z]]
//
// Z ------- metaClass -----> ExpandoMetaClass@39a867
//
//
// b ------- metaClass -----> HandleMetaClass@d88aa2 --- delegate ---> ExpandoMetaClass@d88aa2
// ¿Por qué no se pasa a: b ------- metaClass ---> ExpandoMetaClass@d88aa2
/*
CONCLUSIONES
metaClass es un mal nombre, hay que pensar en una especie de capsula o concha
HandleMetaClass delega en otra metaClass.
Cuando
- se invoca un método en un HandleMetaClass
- se hace setProperty en el HandlemetaClass
- se hace getProperty en el HandlemetaClass
el delegado pasa a ser un ExpandoMetaClass
Las GClases tienen un metaClass que será usado como capsula por sus instancias
(CUIDADO: no confundir con el autentico concepto de meta clase)
Recien creada la clase su metaClass apunta a un HandleMetaClass con delegate MetaClassImpl
Si se "toca" (set,get,invoke) el metaClass, se cambia a un ExpandoMetaClass
Las instancias de una clase tienen su metaClass apuntará a un HandleMetaClass en cualquier caso.
(No entiendo por que no se hace lo mimos que con la clase y se elimina la indirección cuando se puede)
Si se crea una instancia de una clase cuyo metaClass no ha pasado a ExpandoMetaClass
el metaClass de la instancia referenciará el mismo ente que el metaClass de la clase, que es un
HandleMetaClass.
Si se crea una instancia de una clase cuyo metaClass ha pasado a ExpandoMetaClass
el metaClass de la instancia apuntará a un HandleMetaClass nuevo que delegará en el ExpandoMetaClass
referenciado por el metaClass de la clase. En este momento entiendo la necesidad
del HandleMetaClass intermedio, ya que sera el encargado de detectar la necesidad de pasar a ExpandoMetaClass
de la particular de la instancia.
Si tocamos el metaClass de una instancia cuyo metaClass apunta al mismo ente que el metaClass de la clase
o mediante delegacion al ExpandoMetaClass de la clase, se creará un nuevo HandleMetaClass delegando en
un nuevo ExpandoMetaClass exclusivo de la instancia. No entiendo por qué es necesaria esta indirección
ya que no se volverá a cambiar a ExpandoMetaClass de forma automática (creo).
*/
//CLOSURES
class Z {
def make = {
return { print "Hola"}
}
}
def a = new Z()
def f = a.make()
println f.class //class Z$_closure1_closure2
println f.metaClass.class //class org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
println f.metaClass //org.codehaus.groovy.runtime.metaclass.ClosureMetaClass@11570cd[class Z$_closure1_closure2]
f.metaClass.x = 5 //groovy.lang.MissingPropertyException:
// No such property: x for class: org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
/*
https://github.com/groovy/groovy-core/blob/master/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
public final class ClosureMetaClass extends MetaClassImpl
Observamos que esta ClosureMetaClass no se preocupa de pasar a ExpandoMetaClass
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment