Querying methods and properties

In this first recipe about metaprogramming, we begin by looking at the introspection capabilities of Groovy. Introspection is a major feature of the Java language and, by extension, of the Groovy language. Using introspection, we can get the internal information of a class at runtime, including fields, methods, constructors, and so on.

Getting ready

To test out the introspection feature, let's create a couple of Groovy classes:

package org.groovy.cookbook

class Book {

  String title
  Author author
  Long year
  Long pages

  Long getAmazonSalesPosition() {
    new Random().nextInt(1) + 1
  }

  void attachReview(String review) { }

}

class Author {
  String name
  String lastName
}

How to do it...

The following steps offer an example of the introspection capabilities of the language:

  1. To check the type of a class, you can just execute the following code snippet:
    assert 'java.lang.String' == String.name
    assert 'org.groovy.cookbook.Author' == Author.name
  2. To list all the properties of the object:
    Author a = new Author(name: 'Ernest',
                          lastName: 'Hemingway')
    Book book = new Book()
    book.with {
      title = 'The Old Man and the Sea'
      year = 1952
      pages = 200
      author = a
    }
    book.properties.each { println it }

    The output of looping on the instance's properties is as follows:

    title=The Old Man and the Sea
    class=class org.groovy.cookbook.Book
    amazonSalesPosition=1
    year=1952
    pages=200
    metaClass=
      org.codehaus.groovy.runtime.HandleMetaClass
        @41ce774e[groovy.lang.MetaClassImpl@41ce774e[
          class org.groovy.cookbook.Book]]
    author=org.groovy.cookbook.Author@59fac3a2
    
  3. One of the properties returned from the query is metaClass. Through this property, we can access quite many interesting methods to figure out what our class can do. For instance, to check the existence of a property, we can use the following code snippet:
    assert book.metaClass.hasProperty(book, 'pages')
  4. Or list all the methods and properties:
    println '#### METHODS ####'
    book.metaClass.methods.each { println it }
    
    println '#### PROPERTIES ####'
    book.metaClass.properties.each { println it.name }

    Note how the methods' property prints all the methods inherited from Java (such as equals and hashCode) as well as the local methods of the class:

    ### METHODS ####
    public boolean java.lang.Object.equals(java.lang.Object)
    public final native java.lang.Class java.lang.Object.getClass()
    public native int java.lang.Object.hashCode()
    ...
    public void Book.attachReview(java.lang.String)
    public java.lang.Long Book.getAmazonSalesPosition()
    public Author Book.getAuthor()
    public groovy.lang.MetaClass Book.getMetaClass()
    public java.lang.Long Book.getPages()
    ...
    ### PROPERTIES ###
    title
    class
    amazonSalesPosition
    year
    pages
    author
    
  5. Finally, the metaClass gives access to the respondsTo method, to directly interrogate an instance about the presence of a method:
    assert book.metaClass.respondsTo(book,'getAmazonSalesPosition')
    assert book.metaClass.respondsTo(book,'attachReview', String)

    The respondsTo method can be directly invoked on any object, as it is also exposed on the Groovy enhanced java.lang.Object class:

    assert book.respondsTo('attachReview', String)

How it works...

Every class in the class loader has a reference to an object of type metaClass. This metaClass maintains the list of all methods and properties of a given class, starting with the bytecode information and adding the additional methods that Groovy knows about by default (DefaultGroovyMethods). Normally, all instances of a class share the same metaClass. However, Groovy allows per instance metaclasses, that is, different instances of a class that may refer to different metaclasses.

The first example in Step 1 is nothing more than calling getClass().getName() on a Java class; therefore, piggybacking on the Java reflection capabilities. The remaining examples are more interesting because they leverage the dynamic properties of the Groovy language through the metaClass attribute. The respondsTo method, in particular, is useful when writing a dynamic code; for example, populating an arbitrary object from some data on a file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.86.183