What methods does my Groovy/Grails class have?

2008/05/7

If you’ve ever wondered what methods a groovy class has available for you to call, all you need to do is ask the metaClass:

"foo".metaClass.methods*.name

Result:

["equals", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait", "wait", 
"wait", "charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo", 
"compareTo", "compareToIgnoreCase", "concat", "contains", "contentEquals", 
"contentEquals", "copyValueOf", "copyValueOf", "endsWith", "equals", 
"equalsIgnoreCase", "format", "format", "getBytes", "getBytes",
 "getBytes", "getChars", "hashCode", "indexOf", "indexOf", "indexOf", 
"indexOf", "intern", "lastIndexOf", "lastIndexOf", "lastIndexOf", "lastIndexOf", 
"length", "matches", "offsetByCodePoints", "regionMatches", "regionMatches", 
"replace", "replace", "replaceAll", "replaceFirst", "split", "split", "startsWith",
 "startsWith", "subSequence", "substring", "substring", "toCharArray", 
"toLowerCase", "toLowerCase", "toString", "toUpperCase", "toUpperCase", 
"trim", "valueOf", "valueOf", "valueOf", "valueOf", "valueOf", "valueOf", 
"valueOf", "valueOf", "valueOf"]

There’s a lot of duplication in there, and the order is random, so I’ll often fix that like this:

"foo".metaClass.methods*.name.sort().unique()

Result:

["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo",
 "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", 
"endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars",
 "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", 
"notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", "replaceAll",
 "replaceFirst", "split", "startsWith", "subSequence", "substring", "toCharArray", 
"toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]


If you haven’t seen that “*” in metaClass.methods*.name, that’s known as the Spread Operator and it’s essentially the same thing as saying

"foo".metaClass.methods.collect { method -> method.name }.sort().unique()

If you’re using Grails and want to know what methods are on your Author class, looking at the groovy class file will give you a clue if you know the patterns, but it can be easy to forget what the exact convention is:

class Author {
	String name
	def hasMany = [books: Book]
}

Just start up a grails console and ask an Author what it can do:

println new Author().metaClass.methods*.name.sort().unique()

This will result in:

["$static_methodMissing", "<init>", "asType", "clearErrors", "create", 
"decodeBase64", "decodeHTML", "decodeJSON", "decodeJavaScript",
"decodeURL", "decodeXML", "encodeAsBase64", "encodeAsHTML",
 "encodeAsJSON", "encodeAsJavaScript", "encodeAsURL", "encodeAsXML", 
"equals", "findAll", "getBooks", "getClass", "getConstraints", "getErrors", 
"getHasMany", "getId", "getLog", "getMetaClass", "getName", "getProperties", 
"getProperty", "getVersion", "hasErrors", "hashCode", "ident", "invokeMethod", 
"methodMissing", "notify", "notifyAll", "setBooks", "setErrors", "setHasMany",
"setId", "setMetaClass", "setName", "setProperties", "setProperty", 
"setVersion", "toString", "validate", "wait"]

In there, you can see the methods that were decorated on the Author object by grails including encodeAs and decode as well as getters and setters for explicit and implicit variables. One limitation of this method is that some methods are only added by grails dynamically once the method is executed. Notice how there isn’t an addToBooks method in the list? That’s because the method really isn’t there right now. It gets added by grails as part of a methodMissing call. We can force grails to decorate our class by calling one of the dynamic methods (like count()):

def a = new Author()
def origMethods = a.metaClass.methods*.name.sort().unique()
// call one of the dynamic methods so grails fully decorates the metaClass
a.count() 
def newMethods = a.metaClass.methods*.name.sort().unique()
println newMethods - origMethods  // what methods got added?

Subtracting the original methods from newly decorated method list will give you this set of dynamic methods that grails adds when you ask for a dynamic method.

["addToBooks", "count", "createCriteria", "delete", "discard", "executeQuery", 
"executeUpdate", "exists", "find", "findAllWhere", "findWhere", "get", "getAll", 
"list", "lock", "merge", "refresh", "removeFromBooks", "save", "withCriteria",
 "withTransaction"]

If you see a method that you want to use, but can’t remember the signature, again, all you have to do is ask:

println new Author().metaClass.methods.findAll {it.name == "withCriteria"}*.parameterTypes

Result showing the 2 method signatures for withCriteria:

[[interface java.util.Map, class groovy.lang.Closure], [class groovy.lang.Closure]]

There is also a properties method on the metaClass that you can query in a similar manner:

println new Author().metaClass.properties*.name.sort().unique()

Result:

["books", "class", "constraints", "errors", "hasMany", "id", "log", "metaClass", 
"name", "properties", "version"]

Knowing about the information that the metaClass puts at your fingertips makes it much easier to poke around in the grails console, or with a simple script. You can learn a lot of hidden features about a class if you just know how to ask.

There are 7 comments in this article:

  1. 2008/05/7Hamlet D'Arcy say:

    This seems a lot nicer than groovy.inspect.Inspector, which is what I’ve been fighting with recently.

  2. 2008/05/14Robert Rees say:

    Thanks for the article, it was a real help when I was looking for an equivalent of Ruby’s “methods”.

  3. 2008/05/16John say:

    Nice! This should do until the groovy / Eclipse plugin is auto-completing properly

  4. 2008/09/4englishteeth.co.uk » Groovy on Grails and my “Test First” impasse say:

    [...] started by Fun with Groovy and the Reflection API and definitely helped by What methods does my Groovy/Grails class have? I distilled my problem to a script and proceeded to dump anything and everything I could think of [...]

  5. 2009/07/30Ted Naleid » Modularizing Groovy Config Files With a Dash of Meta-Programming say:

    [...] is a continuation of a sporadic set of blog posts about some practical uses for groovy [...]

  6. 2009/10/22Pierre Thibault say:

    Does not work. Some methods are missing. For example, if I have a variable referencing a string, I have more methods listed with inspect’ than using the expression you are suggesting. ‘each’ is listed with ‘inspect’ and not listed using your method.

  7. 2009/10/22tednaleid say:

    @Pierre, you’re correct, this method doesn’t show you the meta methods that are on every Object, the ones that most of the time I don’t find interesting. It also contains the static class meta methods that are added by the DefaultGroovyMethods class.

    If you really want to see those methods as well, you can look at the metaMethods collection:

    groovy> "foo".metaClass.metaMethods.name.sort().unique()
     
    Result: [addShutdownHook, any, asType, bitwiseNegate, center, collect, contains, count, decodeBase64, denormalize, dump, each, eachLine, eachMatch, eachWithIndex, every, execute, find, findAll, findIndexOf, findIndexValues, findLastIndexOf, getAt, getChars, getMetaClass, getMetaPropertyValues, getProperties, grep, hasProperty, identity, inject, inspect, invokeMethod, is, isBigDecimal, isBigInteger, isCase, isDouble, isFloat, isInteger, isLong, isNumber, iterator, leftShift, matches, metaClass, minus, multiply, next, normalize, numberAwareCompareTo, padLeft, padRight, plus, previous, print, printf, println, putAt, readLines, replace, replaceAll, replaceFirst, respondsTo, reverse, setMetaClass, size, sleep, split, splitEachLine, sprintf, toBigDecimal, toBigInteger, toBoolean, toCharacter, toDouble, toFloat, toInteger, toList, toLong, toShort, toString, toURI, toURL, tokenize, use, with]

    If you really want a full list of ALL methods, you can add the methods to the metaMethods and sort + unique that:

    groovy> ("foo".metaClass.methods.name + "foo".metaClass.metaMethods.name).sort().unique()
     
    Result: [addShutdownHook, any, asType, bitwiseNegate, center, charAt, codePointAt, codePointBefore, codePointCount, collect, compareTo, compareToIgnoreCase, concat, contains, contentEquals, copyValueOf, count, decodeBase64, denormalize, dump, each, eachLine, eachMatch, eachWithIndex, endsWith, equals, equalsIgnoreCase, every, execute, find, findAll, findIndexOf, findIndexValues, findLastIndexOf, format, getAt, getBytes, getChars, getClass, getMetaClass, getMetaPropertyValues, getProperties, grep, hasProperty, hashCode, identity, indexOf, inject, inspect, intern, invokeMethod, is, isBigDecimal, isBigInteger, isCase, isDouble, isEmpty, isFloat, isInteger, isLong, isNumber, iterator, lastIndexOf, leftShift, length, matches, metaClass, minus, multiply, next, normalize, notify, notifyAll, numberAwareCompareTo, offsetByCodePoints, padLeft, padRight, plus, previous, print, printf, println, putAt, readLines, regionMatches, replace, replaceAll, replaceFirst, respondsTo, reverse, setMetaClass, size, sleep, split, splitEachLine, sprintf, startsWith, subSequence, substring, toBigDecimal, toBigInteger, toBoolean, toCharArray, toCharacter, toDouble, toFloat, toInteger, toList, toLong, toLowerCase, toShort, toString, toURI, toURL, toUpperCase, tokenize, trim, use, valueOf, wait, with]

    As I said, most of the time just looking at the “methods” gives me what I want, but this is the way to get the exhaustive list.

Write a comment: