BeanUtils.java 11.2 KB
Newer Older
Matt Tucker's avatar
Matt Tucker committed
1 2 3 4 5 6 7 8 9 10 11 12
/**
 * $Revision: 243 $
 * $Date: 2004-11-09 10:37:52 -0800 (Tue, 09 Nov 2004) $
 *
 * Copyright (C) 2004 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */

package org.jivesoftware.util;

13 14 15 16 17 18
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
Matt Tucker's avatar
Matt Tucker committed
19 20 21
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
22
import java.util.*;
Matt Tucker's avatar
Matt Tucker committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

/**
 * A utility class that provides methods that are useful for dealing with
 * Java Beans.
 */
public class BeanUtils {

    /**
     * The date format recognized for parsing/formattig dates.
     */
    public static final String DATE_FORMAT = "MM/dd/yyyy";

    private static DateFormat dateFormatter = new SimpleDateFormat(DATE_FORMAT);

    /**
     * Sets the properties of a Java Bean based on the String name/value pairs in
     * the specifieed Map. Because this method has to know how to convert a
     * String value into the correct type for the bean, only a few bean property
     * types are supported. They are: String, boolean, int, long, float, double,
     * Color, and Class.<p>
     *
     * If key/value pairs exist in the Map that don't correspond to properties
     * of the bean, they will be ignored.
     *
     * @param bean the JavaBean to set properties on.
     * @param properties String name/value pairs of the properties to set.
     */
50
    public static void setProperties(Object bean, Map<String, String> properties) {
Matt Tucker's avatar
Matt Tucker committed
51 52
        try {
            // Loop through all the property names in the Map
53
            for (String propName : properties.keySet()) {
Matt Tucker's avatar
Matt Tucker committed
54 55 56 57 58 59 60 61 62 63
                try {
                    // Create a property descriptor for the named property. If
                    // the bean doesn't have the named property, an
                    // Introspection will be thrown.
                    PropertyDescriptor descriptor = new PropertyDescriptor(
                            propName, bean.getClass());
                    // Load the class type of the property.
                    Class propertyType = descriptor.getPropertyType();
                    // Get the value of the property by converting it from a
                    // String to the correct object type.
64
                    Object value = decode(propertyType, properties.get(propName));
Matt Tucker's avatar
Matt Tucker committed
65
                    // Set the value of the bean.
66
                    descriptor.getWriteMethod().invoke(bean, value);
Matt Tucker's avatar
Matt Tucker committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
                }
                catch (IntrospectionException ie) {
                    // Ignore. This exception means that the key in the map
                    // does not correspond to a property of the bean.
                }
                catch (InvocationTargetException ite) {
                    // Ignore. This exception most often occurs when a
                    // value in the map is null and the target method doesn't
                    // support null properties.
                }
            }
        }
        catch (Exception e) {
            Log.error(e);
        }
    }

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    /**
     * Sets the properties of a Java Bean based on the request's properties. Because
     * this method has to know how to convert a String value into the correct type
     * for the bean, only a few bean property types are supported. They are: String,
     * boolean, int, long, float, double, Color, and Class.<p>
     *
     * If key/value pairs exist in the Map that don't correspond to properties
     * of the bean, they will be ignored.
     *
     * @param bean the JavaBean to set properties on.
     * @param request the HTTP request.
     */
    public static void setProperties(Object bean, HttpServletRequest request) {
        for (Enumeration propNames = request.getParameterNames(); propNames.hasMoreElements();) {
            String propName = (String) propNames.nextElement();
            try {
                // Create a property descriptor for the named property. If
                // the bean doesn't have the named property, an
                // Introspection will be thrown.
                PropertyDescriptor descriptor = new PropertyDescriptor(
                        propName, bean.getClass());
                // Load the class type of the property.
                Class propertyType = descriptor.getPropertyType();
                // Get the value of the property by converting it from a
                // String to the correct object type.
                Object value = decode(propertyType, request.getParameter(propName));
                // Set the value of the bean.
                descriptor.getWriteMethod().invoke(bean, value);
            }
            catch (IntrospectionException ie) {
                // Ignore. This exception means that the key in the map
                // does not correspond to a property of the bean.
            }
            catch (InvocationTargetException ite) {
                // Ignore. This exception most often occurs when a
                // value in the map is null and the target method doesn't
                // support null properties.
            }
            catch (IllegalAccessException e) {
                Log.error(e);
            }
            catch (Exception e) {
                Log.error(e);
            }
        }
    }

Matt Tucker's avatar
Matt Tucker committed
131 132 133 134 135 136 137 138 139 140
    /**
     * Gets the properties from a Java Bean and returns them in a Map of String
     * name/value pairs. Because this method has to know how to convert a
     * bean property into a String value, only a few bean property
     * types are supported. They are: String, boolean, int, long, float, double,
     * Color, and Class.
     *
     * @param bean a Java Bean to get properties from.
     * @return a Map of all properties as String name/value pairs.
     */
141 142
    public static Map<String, String> getProperties(Object bean) {
        Map<String, String> properties = new HashMap<String, String>();
Matt Tucker's avatar
Matt Tucker committed
143 144 145 146 147 148 149 150
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            // Loop through all properties of the bean.
            PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
            String [] names = new String[descriptors.length];
            for (int i=0; i<names.length; i++) {
                // Determine the property name.
                String name = descriptors[i].getName();
151
                //Class type = descriptors[i].getPropertyType();
Matt Tucker's avatar
Matt Tucker committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
                // Decode the property value using the property type and
                // encoded String value.
                Object value = descriptors[i].getReadMethod().invoke(bean,(java.lang.Object[]) null);
                // Add to Map, encoding the value as a String.
                properties.put(name, encode(value));
            }
        }
        catch (Exception e) {
            Log.error(e);
        }
        return properties;
    }

    /**
     * Returns the PropertyDescriptor array for the specified Java Bean Class.
     * The method also does a special check to see of the bean has a BeanInfo
     * class that extends the JiveBeanInfo class. If yes, we load the
     * PropertyDescriptor array directly from that BeanInfo class rather than
     * through the Introspector in order to preserve the desired ordering of
     * properties.
     *
     * @param beanClass the Class of the JavaBean.
     * @return the PropertyDescriptor array for the specified Java Bean Class.
175
     * @throws java.beans.IntrospectionException
Matt Tucker's avatar
Matt Tucker committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
     */
    public static PropertyDescriptor[] getPropertyDescriptors(Class beanClass)
            throws IntrospectionException
    {
        // See if the Java Bean has a BeanInfo class that implements
        // JiveBeanInfo. If so, return the PropertyDescriptor from that
        // class. This will bypass properties of parent classes, but this is
        // the normal behavior of classes that implement JiveBeanInfo.
        try {
            JiveBeanInfo beanInfo = (JiveBeanInfo)ClassUtils.forName(
                    beanClass.getName() + "BeanInfo").newInstance();
            return beanInfo.getPropertyDescriptors();
        }
        catch (Exception e) {
            // Ignore.
        }
        // Otherwise, return the PropertyDescriptors from the Introspector.
        return Introspector.getBeanInfo(beanClass).getPropertyDescriptors();
    }

    /**
     * Encodes a bean property value as a String. If the object type is not
     * supported, null will be returned.
     *
     * @param value an Object to encode in a String representation.
201
     * @return the encoded bean.
Matt Tucker's avatar
Matt Tucker committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
     */
    private static String encode(Object value) {
        if (value instanceof String) {
            return (String)value;
        }
        if (value instanceof Boolean ||
            value instanceof Integer ||
            value instanceof Long ||
            value instanceof Float ||
            value instanceof Double)
        {
            return value.toString();
        }
        if (value instanceof Date) {
            try {
                return dateFormatter.format((Date)value);
            }
            catch (Exception ignored) {
                // Ignore.
            }
        }
        if (value instanceof Color) {
            Color color = (Color)value;
            return color.getRed() +","+ color.getGreen() +","+ color.getBlue();
        }
        if (value instanceof Class) {
            return ((Class)value).getName();
        }
        return null;
    }

    /**
     * Decodes a String into an object of the specified type. If the object
     * type is not supported, null will be returned.
     *
     * @param type the type of the property.
     * @param value the encode String value to decode.
     * @return the String value decoded into the specified type.
240
     * @throws Exception
Matt Tucker's avatar
Matt Tucker committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
     */
    private static Object decode(Class type, String value) throws Exception {
        if (type.getName().equals("java.lang.String")) {
            return value;
        }
        if (type.getName().equals("boolean")) {
            return Boolean.valueOf(value);
        }
        if (type.getName().equals("int")) {
            return Integer.valueOf(value);
        }
        if (type.getName().equals("long")) {
            return Long.valueOf(value);
        }
        if (type.getName().equals("float")) {
            return Float.valueOf(value);
        }
        if (type.getName().equals("double")) {
            return Double.valueOf(value);
        }
        if (type.getName().equals("java.util.Date")) {
            try {
                return dateFormatter.parse(value);
            }
            catch (Exception ignored) {
                // Ignore.
            }
        }
        if (type.getName().equals("java.awt.Color")) {
            StringTokenizer tokens = new StringTokenizer(value, ",");
            int red = Integer.parseInt(tokens.nextToken());
            int green = Integer.parseInt(tokens.nextToken());
            int blue = Integer.parseInt(tokens.nextToken());
            return new Color(red, green, blue);
        }
        if (type.getName().equals("java.lang.Class")) {
            return ClassUtils.forName(value);
        }
        return null;
    }

    // This class is not instantiable.
    private BeanUtils() {
        // do nothing.
    }
}