If I add a meta method to a class, I would expect it to show up in Class.metaClass.metaMethods
. But this seems not to be the case. In particular, if I do this:
class Example {
def realFoo() { "foo" }
}
Example.metaClass.metaFoo = { -> "foo" }
def reals = Example.metaClass.methods*.name.grep{it.contains("Foo")}
def metas = Example.metaClass.metaMethods*.name.grep{it.contains("Foo")}
println "reals = $reals, metas = $metas"
I would expect output of reals = [realFoo], metas = [metaFoo]
, but I actually get reals = [realFoo, metaFoo], metas = []
.
It looks like new meta methods are stored in methods, not metaMethods. So, what is the difference between metaClass.methods
and metaClass.metaMethods
?
MetaMethods contains those methods that are decorated on the class by Groovy, but aren't actually a direct part of the class or it's inheritance structure, or that have been manually inserted into the class through the metaClass.
These are defined in the DefaultGroovyMethods class.
Depending on the type of object you're instantiating, it's mostly iterators like each, collect, find, etc.
This modification to your code shows the methods that are meta only, "real" only, and shared:
class Example {
def realFoo() { "foo" }
}
Example.metaClass.metaFoo = { -> "foo" }
def reals = Example.metaClass.methods.name.sort().unique()
def metas = Example.metaClass.metaMethods.name.sort().unique()
def metaOnly = metas - reals
def realOnly = reals - metas
def shared = reals.findAll { metas.contains(it) }
println """
metaOnly = $metaOnly
realOnly = $realOnly
shared = $shared
"""
Result:
metaOnly = [addShutdownHook, any, asBoolean, asType, collect, dump, each, eachWithIndex, every, find, findAll, findIndexOf, findIndexValues, findLastIndexOf, findResult, getAt, getMetaPropertyValues, getProperties, grep, hasProperty, identity, inject, inspect, is, isCase, iterator, metaClass, print, printf, println, putAt, respondsTo, sleep, split, sprintf, use, with]
realOnly = [equals, getClass, getProperty, hashCode, metaFoo, notify, notifyAll, realFoo, setProperty, wait]
shared = [getMetaClass, invokeMethod, setMetaClass, toString]
All of the metaOnly and shared methods are in DefaultGroovyMethods. All of the "real" methods are on the class itself, or on it's parent class (Object in this case), plus a couple of groovy things directly related to the metaClass to get/set the metaClass as well as getProperty/setProperty and invokeMethod which allow you to override method behavior.
If you want to search through all of the methods to see what exists, I use something like this:
def allMethods = (Example.metaClass.methods + Example.metaClass.metaMethods).name.sort().unique()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With