Java Reflection & Smaltalk-like Method Dispatching
by Barry Feigenbaum 


Example 1:

(a)
class Bird {
    method fly(){ ... }
}
class Plane {
    method fly() { ... }
}
class Angel {
    method fly(){ ... }
}
class Leaf {
    method fly(){ ... }
}

(b)
flyer = new Bird()
flyer.fly()

flyer = new Plane()
flyer.fly()

flyer = new Angel()
flyer.fly()

flyer = new Leaf()
flyer.fly()



Listing One

class Test1:
    def method1 (self):
        return "Test1"
class Test2:
    def method1 (self):
        return "Test2"
class Test3:
    def method2 (self):
        return "Test3"
class Test4(Test1):
    def method2 (self):
        return "Test4"
class Test5(Test1):
    def method1 (self):
        return "Test5"


Listing Two

def testit (name, receiver, func, default=None):
    o = None
    print
    print "trying", name
    try:
        o = func(receiver)
    except Exception, e:
        print "Exception:", e.__class__, '-', e
        if e.__class__ == AttributeError and default is not None:
            o = default
    print "result of", name, '=', o
    return o


Listing Three

if __name__ == "__main__":
    s = "This is a test string"
    print "For value:", s


Listing Four

    testit('s.find("xxx")', s, lambda x: x.find("xxx"))
    testit('s.find("test")', s, lambda x: x.find("test"))
    testit('s.find("xxx","yyy")', s, lambda x: x.find("xxx", "yyy"))

trying s.find("xxx")
result of s.find("xxx") = -1

trying s.find("test")
result of s.find("test") = 10

trying s.find("xxx","yyy")
exception: exceptions.TypeError - 2nd arg can't be coerced to int
result of s.find("xxx","yyy") = None


Listing Five

    t = Test1()
    testit('t.method1()', t, lambda x: x.method1())
    testit('t.method2()', t, lambda x: x.method2())

trying t.method1()
result of t.method1() = Test1
trying t.method2()
Exception: exceptions.AttributeError - method2
result of t.method2() = None

    t = Test2()
    testit('t.method1()', t, lambda x: x.method1())
    testit('t.method2()', t, lambda x: x.method2())

trying t.method1()
result of t.method1() = Test2
trying t.method2()
Exception: exceptions.AttributeError - method2
result of t.method2() = None


Listing Six

    t = Test3()
    testit('t.method1()', t, lambda x: x.method1())
    testit('t.method2()', t, lambda x: x.method2())

trying t.method1()
Exception: exceptions.AttributeError - method1
result of t.method1() = None
trying t.method2()
result of t.method2() = Test3


Listing Seven

    t = Test4()
    testit('t.method1()', t, lambda x: x.method1())
    testit('t.method2()', t, lambda x: x.method2())

trying t.method1()
result of t.method1() = Test1
trying t.method2()
result of t.method2() = Test4


Listing Eight

    t = Test5()
    testit('t.method1()', t, lambda x: x.method1())
    testit('t.method2()', t, lambda x: x.method2())
    testit('t.method2()', t, lambda x: x.method2(), "default")

trying t.method1()
result of t.method1() = Test5
trying t.method2()
Exception: exceptions.AttributeError - method2
result of t.method2() = None

trying t.method2()
Exception: exceptions.AttributeError - method2
result of t.method2() = default


Listing Nine

void call(Object instance, String name, {Object[] args});
void callStatic(Class owner, String name, {Object[] args});
Object invoke(Object instance, String name, {Object[] args, {Object def}});
Object invokeStatic(Class owner, String name, {Object[] args, {Object def}});


Listing Ten

boolean canInvoke(Object instance, String name, {Object[] args});
boolean canInvokeStatic(Class owner, String name, {Object[] args});
Method findMethod(Class owner, String name, {Object[] args});


Listing Eleven

class Test1 {
    public String method1() {
        return "Test1";
    }
}
class Test2 {
    public String method1() {
        return "Test2";
    }
}
class Test3 {
    public String method2() {
        return "Test3";
    }
}
class Test4 extends Test1 {
    public String method2() {
        return "Test4";
    }
}
class Test5 extends Test1 {
    public String method1() {
        return "Test5";
    }
}


Listing Twelve

Object testit(ReflectionUtilities ru, String msg, Object receiver,
                                      String name) {
        return testit(ru, msg, receiver, name, null);
    }
Object testit(ReflectionUtilities ru, String msg, Object receiver,
                                      String name, Object[] args) {
        return testit(ru, msg, receiver, name, args, null);
    }
Object testit(ReflectionUtilities ru, String msg, Object receiver,
                                     String name, Object[] args, Object def) {
        Object o = null;
        try {
            System.out.println(msg);
            o = ru.invoke(receiver, name, args, def);
        }
        catch (InvokeException e) {
            System.out.println(e.getMessage());
        }
        System.out.println(msg + ": " + o);
        return o;
    }


Listing Thirteen

    ReflectionUtilities ru = ReflectionUtilities.getDefault();
    String s = new String("This is a test string");
    System.out.println("For value: " + s);

For value: This is a test string

    testit(ru, "length()", s, "length");
    testit(ru, "length(\"bad\")=-1", s,
           "length", new Object[] {"bad"}, new Integer(-1));
length()
length(): 21
length("bad")=-1
length("bad")=-1: -1

    testit(ru, "indexOf(\"test\")", s, "indexOf", new Object[] {"test"});
    testit(ru, "indexOf(\"test\", 10)", s, "indexOf", new Object[]
           {"test", new Integer(10)});
    testit(ru, "indexOf(\"test\", 1f)", s, "indexOf", new Object[]
           {"test", new Float(1f)});
    testit(ru, "indexOf()", s, "indexOf", new Object[] {});

indexOf("test")
indexOf("test"): 10
indexOf("test", 10)
indexOf("test", 10): 10
indexOf("test", 1f)
method not found - java.lang.String.indexOf(java.lang.String,java.lang.Float)
indexOf("test", 1f): null
indexOf()
method not found - java.lang.String.indexOf()
indexOf(): null

    testit(ru, "toUpperCase()", s, "toUpperCase");
toUpperCase()
toUpperCase(): THIS IS A TEST STRING

    testit(ru,"startsWith(\"This\")", s,"startsWith", new Object[] {"This"});
    testit(ru,"startsWith(\"That\")", s,"startsWith", new Object[] {"That"});
startsWith("This")
startsWith("This"): true
startsWith("That")
startsWith("That"): false
Listing Fourteen
    Object t;

    t = new Test1();
    testit(ru, "t.method1()", t, "method1");
    testit(ru, "t.method2()", t, "method2");
t.method1()
t.method1(): Test1
t.method2()
method not found - com.ibm.reflect.ReflectionUtilitiesTest$Test1.method2()
t.method2(): null

    t = new Test2();
    testit(ru, "t.method1()", t, "method1");
    testit(ru, "t.method2()", t, "method2");
t.method1()
t.method1(): Test2
t.method2()
method not found - com.ibm.reflect.ReflectionUtiltiesTest$Test2.method2()
t.method2(): null

    t = new Test3();
    testit(ru, "t.method1()", t, "method1");
    testit(ru, "t.method2()", t, "method2");
t.method1()
method not found - com.ibm.reflect.ReflectionUtiltiesTest$Test3.method1()
t.method1(): null
t.method2()
t.method2(): Test3

    t = new Test4();
    testit(ru, "t.method1()", t, "method1");
    testit(ru, "t.method2()", t, "method2");
t.method1()
t.method1(): Test1
t.method2()
t.method2(): Test4

    t = new Test5();
    testit(ru, "t.method1()", t, "method1");
    testit(ru, "t.method2()", t, "method2");
t.method1(): Test5
t.method2()
method not found - com.ibm.reflect.ReflectionUtiltiesTest$Test5.method2()
t.method2(): null




