« August 2006 »
SunMonTueWedThuFriSat
  
1
3
4
5
6
9
11
12
13
16
17
19
20
23
24
26
27
28
31
  
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 411

Powered by Roller Weblogger.
« Previous day (Aug 8, 2006) | Main | Next day (Aug 10, 2006) »
20060810 Thursday August 10, 2006

doesNotUnderstand in Groovy

What is doesNotUnderstand method? From Reflective Facilities in Smalltalk-80 by Brian Foote and Ralph E. Johnson:

When a message is sent to a Smalltalk-80 object, the method dictionaries associated with that object's class and its superclasses are searched at runtime. If none of these classes implement a method for a given message, the Smalltalk virtual machine sends the object the message doesNotUnderstand:. The original message selector and message arguments are bundled together in a Message object and passed as the argument to doesNotUnderstand:. The default method for this message is stored in class Object. This method invokes the Smalltalk debugger, since sending an object a message it does not implement is usually a sign of programmer error. However, objects that override doesNotUnderstand: can intercept unimplemented message at runtime, and process them as they see fit.

Java being a statically typed language, javac will not compile if a method can not be found at compile time. Time to look at some code...



class Main {
   public static void main(String[] args) {
       // see Person class below..
       Person p = new Person();
       System.out.println("Starting...");

       // call methods that are defined in Person class
       p.work();
       p.greet();

       // call methods that are not defined in Person 
       // or it's superclass       
       p.surfTheNet();
       p.writeBlog();
   }
}

class Person {

   public void work() { 
       System.out.println("Okay, I'll work tomorrow!");
   }

   public void greet() { 
       System.out.println("Hello, World!");
   }
  
   public Object invokeMethod(String name, Object args) {
       System.out.println("Why are you calling " + name + "?");
   }
}


If you attempted javac against above program, you will get
Main.java:15: cannot find symbol
symbol  : method surfTheNet()
location: class Person
       p.surfTheNet();
        ^
Main.java:16: cannot find symbol
symbol  : method writeBlog()
location: class Person
       p.writeBlog();
        ^
2 errors

You may have heard and/or used dynamic proxies with Java. With dynamic proxies, you implement all methods of one or more interfaces by a single invoke of an InvocationHandler.

Imagine if you could do something similar for classes as well (not just for interfaces). i.e., all method calls on objects of your class will end-up calling a single (special) "invokeMethod" method. Or think of something slightly restricted. If a method of matching name (and signature) is found in your class (or any of the superclasses) then that method will be called - if no such method is found, then a special method called "invokeMethod" will be called Groovy supports both the options.

Output with above program from Groovy is as follows:
Starting...
Okay, I'll work tomorrow!
Hello, World!
Why are you calling surfTheNet?
Why are you calling writeBlog?

i.e., For the methods not found in Person class, Groovy calls invokeMethod method. Now, what if you want to "trap" all method calls, regardless of whether the method is defined in your class or not. It turns out that you can that in Groovy. We make the following change to Person class:



class Person implements GroovyInterceptable {
   public void work() { 
       System.out.println("Okay, I'll work tomorrow!");
   }

   public void greet() { 
       System.out.println("Hello, World!");
   }

   public Object invokeMethod(String name, Object args) {
       System.out.println("Why are you calling " + name + "?");
   }
}


Output from Groovy after the above change is as follows:
Starting...
Why are you calling work?
Why are you calling greet?
Why are you calling surfTheNet?
Why are you calling writeBlog?

When you implement groovy.lang.GroovyInterceptable interface, you are essentially saying that for any method call on the objects of this class, call invokeMethod method.

What about properties? You can implement special methods getProperty(String) and putProperty(String, Object) methods for properties. These are used in the implementation of groovy.util.GroovyMBean - which I mentioned in my blog entry titled Groovier jconsole.

Actually, Groovy's Meta Object Protocol is slightly more complex than what I described. But then that is a topic for another blog entry .... :-)



( Aug 10 2006, 11:24:34 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Copyright (C) 2005, A. Sundararajan's Weblog