JavaBean Proxies

Thornton Rose

Published as "JavaBean Proxies", 8/13/2001, Gamelan.com.

Copyright © 2001, Thornton Rose.


While developing a small database application for keeping a work journal, I discovered I needed a way to map JavaBean properties to JTable columns. This led to creation of a component for accessing JavaBean properties by name at runtime -- in other words, a JavaBean proxy. In this article, I illustrate my simple JavaBean proxy and show how JavaBean proxies can be created with the new dynamic proxy classes in JDK 1.3.

Tools

To use the code from this article, you will need the following tools:

(Note: For the simple bean proxy code, you can actually use JDK 1.2. You only need JDK 1.3 for the dynamic bean proxy code.)

Bean Interrogation

In order to access a JavaBean -- or any java class for that matter -- dynamically at runtime, you first need to get information about the capabilities of the class, or "class meta data". This information can come from two sources: BeanInfo classes and low-level analysis of the bean class. BeanInfo classes -- extensions of java.beans.SimpleBeanInfo or implementations of java.beans.BeanInfo -- provide descriptors of the properties, events, and methods of a class. They are associated with a class by the simple naming convention class name + "BeanInfo".

Here are some examples of beans and BeanInfo:

To get class metadata, you use can use introspection and/or reflection. Introspection is done with java.beans.Introspector, which will provide a java.beans.BeanInfo object that describes the properties, events, and methods of the class. Reflection is done with java.lang.Class, which will provide objects that let you access fields and methods of the class.

ClassInfo illustrates using introspection and reflection. It loads a given class, gets the class metadata, then prints the properties, events, and methods that are exposed by the class. Try it on Quark and Photon.

Simple Bean Proxy

Once you have the metadata for a class, you can access instances of that class. Here is an example of dynamically creating an instance of Quark and invoking its spin() method:

   // Load class.
   Class quarkClass = Class.forName("Quark");

   // Create instance.
   Object quark = quarkClass.newInstance();

   // Get spin() method.
   Method spinMethod = quarkClass.getMethod("spin", new Class[] {});

   // Invoke spin() method.
   spinMethod.invoke(quark, new Object[] {});

BeanProxy is a reusable component that implements the mechanism shown above and acts as a proxy for instances of a given class. It provides the following operations:

Technically, BeanProxy does not need the set() and get() methods, but I added them so that using a proxy object would be similar to using the target object. Here is an example of the differences in property access:

   // Set property "color" on real object.
   aPhoton.setColor("green");

   // Set property "color" via proxy set() method.
   aPhotonProxy.set("color", "green");

   // Set property "color" via proxy invoke() method.
   aPhotonProxy.invoke("setColor", new Class[] { String.class },
      new Object[] { "green" });

Here is an example of using BeanProxy to create a proxy for an instance of Quark and invoking some methods on it:

   // Load class.
   Class beanClass = Class.forName("Quark");

   // Create proxy for instance.
   BeanProxy proxy = new BeanProxy(beanClass.newInstance());

   // Call methods.
   proxy.set("color", "strawberry");
   proxy.invoke("spin", new Object[] {});

Dynamic Bean Proxy

Dynamic proxy classes are one of the new features of JDK 1.3. A dynamic proxy provides access to a target object via interfaces that are specified at runtime and implemented by the proxy. When methods of these interfaces are invoked, they are dispatched to an invocation handler -- a class that implements java.lang.reflect.InvocationHandler -- which handles method invocations on the target object. This design gives dynamic proxies the following advantages over BeanProxy:

However, dynamic proxy classes also have some disadvantages (at least in comparison to BeanProxy):

The class java.lang.reflect.Proxy is used to create dynamic proxies. QuarkTrace is an example of using it to create a dynamic proxy that adds method call tracing to any class that implements IQuark. Try it on Quark and AntiQuark.

Can BeanProxy be implemented as a dynamic proxy? Yes. Here is one way:

  1. Create an interface (i.e., an actual Java interface) for the public methods of BeanProxy.
  2. Create a factory class for creating the proxies.
  3. Implement an IBeanProxy and an InvocationHandler.

Here is the code:

Here is an example of using DynamicBeanProxy to create a proxy for an instance of AntiQuark and invoking some methods on it:

   // Load class.
   Class beanClass = Class.forName("AntiQuark");

   // Create proxy for instance.
   IBeanProxy proxy = new DynamicBeanProxy(beanClass.newInstance());

   // Call methods.
   proxy.set("color", "black");
   proxy.invoke("spin", new Object[] {});

Uses

So why would you want to use object proxies? Here are some things you can do with them:

Resources