Last active
December 11, 2015 19:28
-
-
Save joseanpg/4648339 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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