Mega Code Archive

 
Categories / Java Tutorial / Development
 

Get and set properties on a bean

/*  * The contents of this file are subject to the Sapient Public License  * Version 1.0 (the "License"); you may not use this file except in compliance  * with the License. You may obtain a copy of the License at  * http://carbon.sf.net/License.html.  *  * Software distributed under the License is distributed on an "AS IS" basis,  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for  * the specific language governing rights and limitations under the License.  *  * The Original Code is The Carbon Component Framework.  *  * The Initial Developer of the Original Code is Sapient Corporation  *  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.  */ import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.StringTokenizer; /**  * This class implements the ability to get and set properties on a  * bean.  This included the concept of embedded properties that may  * be referenced like <code>Bean.property.property.property</code>.  *  * Copyright 2002 Sapient  * @since carbon 1.0  * @author Greg Hinkle, January 2002  * @version $Revision: 1.11 $ ($Author: dvoet $)  */ public final class BeanUtil {     /**      * String used to separate multiple properties inside of embedded      * beans.      */     private static final String PROPERTY_SEPARATOR = ".";     /**      * An empty class array used for null parameter method reflection      */     private static Class[] NO_PARAMETERS_ARRAY = new Class[] {     };     /**      * an empty object array used for null parameter method reflection      */     private static Object[] NO_ARGUMENTS_ARRAY = new Object[] {     };     /**      * The constructor is private so that <tt>new</tt> cannot be used.      */     private BeanUtil() {     }     /**      * Retreives a property descriptor object for a given property.      *       * Uses the classes in <code>java.beans</code> to get back      * a descriptor for a property.  Read-only and write-only      * properties will have a slower return time.      *       *      * @param propertyName The programmatic name of the property      * @param beanClass The Class object for the target bean.      *                  For example sun.beans.OurButton.class.      * @return a PropertyDescriptor for a property that follows the      *         standard Java naming conventions.      * @throws PropertyNotFoundException indicates that the property      *         could not be found on the bean class.      */     private static final PropertyDescriptor getPropertyDescriptor(         String propertyName,         Class beanClass) {         PropertyDescriptor resultPropertyDescriptor = null;         char[] pNameArray = propertyName.toCharArray();         pNameArray[0] = Character.toLowerCase(pNameArray[0]);         propertyName = new String(pNameArray);         try {             resultPropertyDescriptor =                 new PropertyDescriptor(propertyName, beanClass);         } catch (IntrospectionException e1) {             // Read-only and write-only properties will throw this             // exception.  The properties must be looked up using             // brute force.             // This will get the list of all properties and iterate             // through looking for one that matches the property             // name passed into the method.             try {                 BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);                 PropertyDescriptor[] propertyDescriptors =                     beanInfo.getPropertyDescriptors();                 for (int i = 0; i < propertyDescriptors.length; i++) {                     if (propertyDescriptors[i]                         .getName()                         .equals(propertyName)) {                         // If the names match, this this describes the                         // property being searched for.  Break out of                         // the iteration.                         resultPropertyDescriptor = propertyDescriptors[i];                         break;                     }                 }             } catch (IntrospectionException e2) {                 e2.printStackTrace();             }         }         // If no property descriptor was found, then this bean does not         // have a property matching the name passed in.         if (resultPropertyDescriptor == null) {             System.out.println("resultPropertyDescriptor == null");         }         return resultPropertyDescriptor;     }     /**      * Gets the specified attribute from the specified object.  For example,      * <code>getObjectAttribute(o, "address.line1")</code> will return      * the result of calling <code>o.getAddress().getLine1()</code>.      *      * The attribute specified may contain as many levels as you like. If at      * any time a null reference is acquired by calling one of the successive      * getter methods, then the return value from this method is also null.      *      * When reading from a boolean property the underlying bean introspector      * first looks for an is&lt;Property&gt; read method, not finding one it will      * still look for a get&lt;Property&gt; read method.  Not finding either, the      * property is considered write-only.      *      * @param bean the bean to set the property on      * @param propertyNames the name of the propertie(s) to retrieve.  If this is      *        null or the empty string, then <code>bean</code> will be returned.      * @return the object value of the bean attribute      *      * @throws PropertyNotFoundException indicates the the given property      *         could not be found on the bean      * @throws NoSuchMethodException Not thrown      * @throws InvocationTargetException if a specified getter method throws an      *   exception.      * @throws IllegalAccessException if a getter method is      *   not public or property is write-only.      */     public static Object getObjectAttribute(Object bean, String propertyNames)         throws             NoSuchMethodException,             InvocationTargetException,             IllegalAccessException {         Object result = bean;         StringTokenizer propertyTokenizer =             new StringTokenizer(propertyNames, PROPERTY_SEPARATOR);         // Run through the tokens, calling get methods and         // replacing result with the new object each time.         // If the result equals null, then simply return null.         while (propertyTokenizer.hasMoreElements() && result != null) {             Class resultClass = result.getClass();             String currentPropertyName = propertyTokenizer.nextToken();             PropertyDescriptor propertyDescriptor =                 getPropertyDescriptor(currentPropertyName, resultClass);             Method readMethod = propertyDescriptor.getReadMethod();             if (readMethod == null) {                 throw new IllegalAccessException(                     "User is attempting to "                         + "read from a property that has no read method.  "                         + " This is likely a write-only bean property.  Caused "                         + "by property ["                         + currentPropertyName                         + "] on class ["                         + resultClass                         + "]");             }             result = readMethod.invoke(result, NO_ARGUMENTS_ARRAY);         }         return result;     }     /**      * Sets the specified attribute on the specified object.  For example,      * <code>getObjectAttribute(o, "address.line1", value)</code> will call      * <code>o.getAddress().setLine1(value)</code>.      *      * The attribute specified may contain as many levels as you like. If at      * any time a null reference is acquired by calling one of the successive      * getter methods, then a <code>NullPointerException</code> is thrown.      *      * @param bean the bean to call the getters on      * @param propertyNames the name of the attribute(s) to set.  If this is      *        null or the empty string, then an exception is thrown.      * @param value the value of the object to set on the bean property      *      * @throws PropertyNotFoundException indicates the the given property      *         could not be found on the bean      * @throws IllegalArgumentException if the supplied parameter is not of      *   a valid type      * @throws NoSuchMethodException never      * @throws IllegalAccessException if a getter or setter method is      *   not public or property is read-only.      * @throws InvocationTargetException if a specified getter method throws an      *   exception.      */     public static void setObjectAttribute(         Object bean,         String propertyNames,         Object value)         throws             IllegalAccessException,             IllegalArgumentException,             InvocationTargetException,             NoSuchMethodException {         Object result = bean;         String propertyName = propertyNames;         // Check if this has some embedded properties.  If it does, use the         // getObjectAttribute to get the proper object to call this on.         int indexOfLastPropertySeparator =             propertyName.lastIndexOf(PROPERTY_SEPARATOR);         if (indexOfLastPropertySeparator >= 0) {             String embeddedProperties =                 propertyName.substring(0, indexOfLastPropertySeparator);             // Grab the final property name after the last property separator             propertyName =                 propertyName.substring(                     indexOfLastPropertySeparator + PROPERTY_SEPARATOR.length());             result = getObjectAttribute(result, embeddedProperties);         }         Class resultClass = result.getClass();         PropertyDescriptor propertyDescriptor =             getPropertyDescriptor(propertyName, resultClass);         Method writeMethod = propertyDescriptor.getWriteMethod();         if (writeMethod == null) {             throw new IllegalAccessException(                 "User is attempting to write "                     + "to a property that has no write method.  This is likely "                     + "a read-only bean property.  Caused by property ["                     + propertyName                     + "] on class ["                     + resultClass                     + "]");         }         writeMethod.invoke(result, new Object[] { value });     } }