ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Dynamic Delegation and Its Applications
Pages: 1, 2, 3

Exercise 5. Create Delegation Object for the Object of a Java Core Class

Did you ever want to delegate an object of an existing Java core class? Delegate it as usual.


//DateTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;
import java.util.Date;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;

public class DateTest {
    public static void main(String[] args) {
        Date date = new Date();
        DelegationInvocationHandler handler = 
            new DateClassHandler();
        Date delegation = (Date) DelegationGenerator
                .newDelegationInstance(date, handler);
        System.out.println("Delegation class = " +
            delegation.getClass().getName());
        System.out.println("True date = " +
            date.getTime());
        System.out.println("Delegation date = " +
            delegation.getTime());
    }
}

class DateClassHandler extends DummyInvocationHandler {
    public Object invokeAfter(Object bean,
                    Method method, Object[] args,
                    Object result) throws Throwable {
        if (method.getName().equals("getTime")) {
            return new Long(((Long)result).longValue() - 1000);
        }
        return super.invokeAfter(bean, method, args, result);
    }
}

Output:


Delegation class = org.jingle.util.dydelegation.Date_Delegation_0
True date = 1099380377665
Delegation date = 1099380376665

When creating a delegation class for a Java core class, the delegation class will not be in the same package as the Java core class, because the Java security model does not allow a user-defined ClassLoader to define a class in a package starting with java.

DateClassHandler catches the getTime() method call in invokeAfter(), and makes the return value 1000 less than the normal return value.

Advanced Usage

Exercise 6. Simulate Proxy Behavior

Can Dynamic Delegation do what Proxy does? Absolutely! Dynamic Delegation covers the functions of Proxy. Given a proper delegation handler, it can simulate the behavior of a Java Proxy.


// ProxyTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;

public class ProxyTest {
    public static void main(String[] args) {
        DelegationInvocationHandler handler = new ProxyHandler();
        Object delegation =
            DelegationGenerator.newDelegationInstance(null,
                new Class[] { Idel1.class, Idel2.class },
                null, handler);
        ((Idel1) delegation).idel1();
        ((Idel2) delegation).idel2();
    }
}

class ProxyHandler extends DummyInvocationHandler {
    public boolean invokeBefore(Object bean,
            Method method, Object[] args)
            throws Throwable {
        return false;
    }

    public Object invokeAfter(Object bean, 
            Method method, Object[] args,
            Object result) throws Throwable {
        String name = method.getName();
        if (name.equals("idel1"))
            System.out.println("Hello from idel1");
        else if (name.equals("idel2"))
            System.out.println("Hello from idel2");
        return super.invokeAfter(bean, method, args, result);
    }
}

Output:


Hello from idel1
Hello from idel2

ProxyHandler returns false in invokeBefore(), which means all of the method calls on the delegation object will not be delegated to the original object. It uses invokeAfter() to define the delegation behavior as being what Proxy does.

DelegationGenerator.newDelegationInstance() has another version. It contains four arguments:

  • The Object to be delegated.

    This can be null. If it is not null, it must be an instance of all of the given classes and interfaces.

  • An array of Class to be delegated.

    This can contain multiple interfaces and, at most, one class.

  • Delegation class name.

    If null, a system-generated name will be provided.

  • A DelegationInvocationHandler instance, which is used to define the delegation's behavior.

From the output, we can see that the delegation object is an instance of both Idel1 and Idel2. Its behavior is just what is defined in the handler.

Exercise 7. Partial Delegation

Until now, we've delegated all of the functions of the specific object. How about just delegating part of the object's functions?


//MyDate.java
package org.jingle.util.dydelegation.sample.bean;

import java.util.Date;

public class MyDate extends Date implements Idel1, Idel2 {
    public void idel1() {
    }

    public void idel2() {
    }
}


// MyDateTest.java
package org.jingle.util.dydelegation.sample;

import java.util.Date;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;
import org.jingle.util.dydelegation.sample.bean.MyDate;

public class MyDateTest {
    public static void main(String[] args) {
        MyDate inst = new MyDate();
        DelegationInvocationHandler handler =
            new DummyInvocationHandler();
        Object delegation = 
            DelegationGenerator.newDelegationInstance(inst,
                new Class[] { Idel1.class, Idel2.class },
                null, handler);
        System.out.println(delegation instanceof Idel1);
        System.out.println(delegation instanceof Idel2);
        System.out.println(delegation instanceof Date);
    }
}

Output:


true
true
false

MyDate extends Date and implements the Idel1 and Idel2 interfaces. DelegationGenerator.newDelegationInstance() uses a MyDate instance as the object instance to be delegated, and limits the delegation scope in Idel1 and Idel2. In other words, the generated delegation object is an instance of Idel1 and Idel2, but not an instance of Date.

Conclusion

The Dunamis project introduces Dynamic Delegation to extend the function of the Java Proxy reflection utility. It can generate delegation for both classes and interfaces at runtime. This article introduces Dynamic Delegation in brief with simple examples. In the real world, Dynamic Delegation can be used in many areas, such as mock objects in unit testing, Java GUI MVC framework, and more.

Reference

Lu Jian is a senior Java architect/developer with four years of Java development experience.


Return to ONJava.com