JavaBean Proxies

Monday Aug 13th 2001 by Thornton Rose

Using object proxies lets you access bean properties by name, augment the behavior of an object, and create a broker object of a JavaBean. Here's how to use them.

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.


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

  • The Java Development Kit (JDK), version 1.3.
  • Your favorite text editor.

(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:

  • Quark is a simple JavaBean (no BeanInfo class).
  • Photon is a simple JavaBean that has a BeanInfo class.
  • PhotonBeanInfo is the BeanInfo class for Photon.

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:

  • BeanProxy(Object bean) -- Create a BeanProxy for the given bean.
  • BeanProxy(Class beanClass) -- Create a BeanProxy for an instance of the given bean class.
  • setBean(Object theBean) -- Set the target bean.
  • Object getBean() -- Get the target bean.
  • Object get(String name) -- Get the value of the named bean property.
  • void set(String name, Object value) -- Set the named bean property to the given value.
  • Object invoke(String name, Class[] types, Object[] parameters) -- Invoke the method that has the given name and accepts the given types, passing it the given parameters.

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.

   // 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:

  • Proxy objects are type-safe.
  • Using the proxy is like using the target object.
  • Method invocations are dispatched through a uniform interface.
  • Method calls can be intercepted and augmented.

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

  • An interface must be created for the target object.
  • Properties cannot be specified by name.
  • The proxy itself cannot expose methods.

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[] {});


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

  • Access bean properties by name (as a string) at runtime, -- e.g., mapping JTable columns or database fields to bean properties.
  • Augment the behavior of an object at runtime -- e.g., adding method call tracing.
  • Create a broker object that delegates to instances of other classes that may not be known until runtime.


About the Author

Thornton Rose is a contract software developer and writer living in Atlanta, Ga.

Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved