import java.beans.*; import java.lang.reflect.*; import java.util.*; /** * DynamicBeanProxy is a version of BeanProxy that is implemented as a JDK 1.3 * dynamic proxy class. * * @author Thornton Rose */ public class DynamicBeanProxy { // Static factory methods -------------------------------------------------- // newProxyInstance(Class): /** * Create a new proxy instance for objects of the given class. */ public static IBeanProxy newProxyInstance(Class theBeanClass) throws Exception { return (IBeanProxy) Proxy.newProxyInstance( theBeanClass.getClassLoader(), new Class[] { IBeanProxy.class }, new BeanProxy(theBeanClass)); } // newProxyInstance(Object): /** * Create a new proxy instance for objects of the class of the given * object and set the target object to the given object. */ public static IBeanProxy newProxyInstance(Object theBean) throws Exception { IBeanProxy proxy = newProxyInstance(theBean.getClass()); proxy.setBean(theBean); return proxy; } // BeanProxy --------------------------------------------------------------- /** * BeanProxy is the actual bean proxy. */ private static class BeanProxy implements InvocationHandler, IBeanProxy { private Object bean; private Class beanClass; private Hashtable pdsByName = new Hashtable(); // Constructors --------------------------------------------------------- // BeanProxy(Class): /** * Construct a proxy for the given class. * * @param theBeanClass The target bean class. */ protected BeanProxy(Class theBeanClass) throws IntrospectionException { BeanInfo bi; PropertyDescriptor[] pds; String name; Method m; // Save reference to bean class. beanClass = theBeanClass; // Build hashtable for bean property descriptors. bi = Introspector.getBeanInfo(beanClass); pds = bi.getPropertyDescriptors(); for (int i = 0; i < pds.length; i ++) { name = pds[i].getName(); pdsByName.put(name, pds[i]); } } // BeanProxy(Object): /** * Construct a proxy for the given bean. * * @param theBean The target bean. */ protected BeanProxy(Object theBean) throws IntrospectionException { this(theBean.getClass()); bean = theBean; } // InvocationHandler ---------------------------------------------------- // invoke(Object, Method, Object[]): /** * Handle invocation of the given method for the given proxy. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(this, args); } // IBeanProxy -------------------------------------------------------------- // getBean(); /** * Return the target bean. */ public Object getBean() { return bean; } // setBean(Object); /** * Set the target bean to the given object. */ public void setBean(Object newBean) { bean = newBean; } // get(String): /** * Get bean property. * * @param name Bean property name. * * @return Bean property value as Object. */ public Object get(String name) throws Exception { PropertyDescriptor pd; Method getter; pd = (PropertyDescriptor) pdsByName.get(name); if (pd == null) { throw new NoSuchFieldException("Unknown property: " + name); } getter = pd.getReadMethod(); if (getter == null) { throw new NoSuchMethodException("No read method for: " + name); } return getter.invoke(bean, new Object[] {}); } // set(String, Object): /** * Set bean property. * * @param name Bean property name. * @param value Bean property value. */ public Object set(String name, Object value) throws Exception { PropertyDescriptor pd; Method setter; pd = (PropertyDescriptor) pdsByName.get(name); if (pd == null) { throw new NoSuchFieldException("Unknown property: " + name); } setter = pd.getWriteMethod(); if (setter == null) { throw new NoSuchMethodException("No write method for: " + name); } return setter.invoke(bean, new Object[] { value } ); } // invoke(String, Class[], Object[]): /** * Invoke named method on target bean. * * @param name Method name. * @param types Parameter types. * @param parameters List of parameters passed to method. * * @return Return value from method (may be null). * * @throws Throwable When any exception occurs. */ public Object invoke(String name, Class[] types, Object[] parameters) throws Exception { return beanClass.getMethod(name, types).invoke(bean, parameters); } } }