9.3 Proxy Objects
Java 1.3 added the Proxy class and
InvocationHandler interface to the
java.lang.reflect package. This pair allows the
creation of synthetic "proxy
objects": objects that implement one or more
specified interfaces, with method invocations handled by an
InvocationHandler object. The key method is
Proxy.newProxyInstance( ). This is an advanced
reflection feature, and it is not commonly needed in day-to-day Java
programming. It is quite useful for certain tasks, however, such as
integrating scripting languages with Java.
Example 9-3 builds on the Command
class. The static create( ) method returns a newly
created proxy object that invokes a specified interface using a
Map that associates Command
objects with method names. The inner class Test
provides a GUI-based demonstration like that included with the
Command example.
Example 9-3. CommandProxy.java
package je3.reflect;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
/**
* This class is an InvocationHandler based on a Map of method names to Command
* objects. When the invoke( ) method is called, the name of the method to be
* invoked is looked up in the map, and the associated Command, if any, is
* invoked. Arguments passed to invoke( ) are always ignored. Note that there
* is no public constructor for this class. Instead, there is a static factory
* method for creating Proxy objects that use an instance of this class.
* Pass the interface to be implemented and a Map of name/Command pairs.
**/
public class CommandProxy implements InvocationHandler {
Map methodMap; // Maps method names to Command objects that implement
// private constructor
private CommandProxy(Map methodMap) { this.methodMap = methodMap; }
// This method implements InvocationHandler, and invokes the Command,
// if any associated with the name of Method m. It ignores args[ ] and
// always returns null.
public Object invoke(Object p, Method m, Object[ ] args) throws Throwable {
String methodName = m.getName( );
Command command = (Command) methodMap.get(methodName);
if (command != null) command.invoke( );
return null;
}
// Return an object that implements the specified interface, using the
// name-to-Command map as the implementation of the interface methods.
public static Object create(Class iface, Map methodMap) {
InvocationHandler handler = new CommandProxy(methodMap);
ClassLoader loader = handler.getClass( ).getClassLoader( );
return Proxy.newProxyInstance(loader, new Class[ ] { iface }, handler);
}
// This is a test class to demonstrate the use of CommandProxy.
static class Test {
public static void main(String[ ] args) throws java.io.IOException {
// Set up a simple GUI
javax.swing.JFrame f = new javax.swing.JFrame("Command Test");
javax.swing.JButton b = new javax.swing.JButton("Hello World");
f.getContentPane( ).add(b, java.awt.BorderLayout.CENTER);
f.pack( );
f.show( );
// Set up the Map of method names to Command objects
Map methodMap = new HashMap( );
methodMap.put("focusGained",Command.parse(b,"setText(\"hello\")"));
methodMap.put("focusLost",Command.parse(b,"setText(\"goodbye\")"));
// Use CommandProxy.create( ) to create a proxy FocusListener
FocusListener l =
(FocusListener)CommandProxy.create(FocusListener.class,
methodMap);
// Use the synthetic FocusListener
b.addFocusListener(l);
}
}
}
 |