Source Code Cross Referenced for BeanUtilsBean.java in  » Library » Apache-commons-beanutils-1.8.0-BETA-src » org » apache » commons » beanutils » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache commons beanutils 1.8.0 BETA src » org.apache.commons.beanutils 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.commons.beanutils;
0019:
0020:        import java.beans.IndexedPropertyDescriptor;
0021:        import java.beans.PropertyDescriptor;
0022:        import java.lang.reflect.Array;
0023:        import java.lang.reflect.InvocationTargetException;
0024:        import java.lang.reflect.Method;
0025:        import java.util.ArrayList;
0026:        import java.util.Collection;
0027:        import java.util.HashMap;
0028:        import java.util.Iterator;
0029:        import java.util.Map;
0030:
0031:        import org.apache.commons.beanutils.expression.Resolver;
0032:        import org.apache.commons.logging.Log;
0033:        import org.apache.commons.logging.LogFactory;
0034:
0035:        /**
0036:         * <p>JavaBean property population methods.</p>
0037:         *
0038:         * <p>This class provides implementations for the utility methods in
0039:         * {@link BeanUtils}.
0040:         * Different instances can be used to isolate caches between classloaders
0041:         * and to vary the value converters registered.</p>
0042:         *
0043:         * @author Craig R. McClanahan
0044:         * @author Ralph Schaer
0045:         * @author Chris Audley
0046:         * @author Rey Francois
0047:         * @author Gregor Rayman
0048:         * @version $Revision: 556229 $ $Date: 2007-07-14 07:11:19 +0100 (Sat, 14 Jul 2007) $
0049:         * @see BeanUtils
0050:         * @since 1.7
0051:         */
0052:
0053:        public class BeanUtilsBean {
0054:
0055:            // ------------------------------------------------------ Private Class Variables
0056:
0057:            /** 
0058:             * Contains <code>BeanUtilsBean</code> instances indexed by context classloader.
0059:             */
0060:            private static final ContextClassLoaderLocal BEANS_BY_CLASSLOADER = new ContextClassLoaderLocal() {
0061:                // Creates the default instance used when the context classloader is unavailable
0062:                protected Object initialValue() {
0063:                    return new BeanUtilsBean();
0064:                }
0065:            };
0066:
0067:            /** 
0068:             * Gets the instance which provides the functionality for {@link BeanUtils}.
0069:             * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
0070:             * This mechanism provides isolation for web apps deployed in the same container.
0071:             *
0072:             * @return The (pseudo-singleton) BeanUtils bean instance
0073:             */
0074:            public static BeanUtilsBean getInstance() {
0075:                return (BeanUtilsBean) BEANS_BY_CLASSLOADER.get();
0076:            }
0077:
0078:            /** 
0079:             * Sets the instance which provides the functionality for {@link BeanUtils}.
0080:             * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
0081:             * This mechanism provides isolation for web apps deployed in the same container.
0082:             * 
0083:             * @param newInstance The (pseudo-singleton) BeanUtils bean instance
0084:             */
0085:            public static void setInstance(BeanUtilsBean newInstance) {
0086:                BEANS_BY_CLASSLOADER.set(newInstance);
0087:            }
0088:
0089:            // --------------------------------------------------------- Attributes
0090:
0091:            /**
0092:             * Logging for this instance
0093:             */
0094:            private Log log = LogFactory.getLog(BeanUtils.class);
0095:
0096:            /** Used to perform conversions between object types when setting properties */
0097:            private ConvertUtilsBean convertUtilsBean;
0098:
0099:            /** Used to access properties*/
0100:            private PropertyUtilsBean propertyUtilsBean;
0101:
0102:            /** A reference to Throwable's initCause method, or null if it's not there in this JVM */
0103:            private static final Method INIT_CAUSE_METHOD = getInitCauseMethod();
0104:
0105:            // --------------------------------------------------------- Constuctors
0106:
0107:            /** 
0108:             * <p>Constructs an instance using new property 
0109:             * and conversion instances.</p>
0110:             */
0111:            public BeanUtilsBean() {
0112:                this (new ConvertUtilsBean(), new PropertyUtilsBean());
0113:            }
0114:
0115:            /** 
0116:             * <p>Constructs an instance using given conversion instances
0117:             * and new {@link PropertyUtilsBean} instance.</p>
0118:             *
0119:             * @param convertUtilsBean use this <code>ConvertUtilsBean</code> 
0120:             * to perform conversions from one object to another
0121:             *
0122:             * @since 1.8.0
0123:             */
0124:            public BeanUtilsBean(ConvertUtilsBean convertUtilsBean) {
0125:                this (convertUtilsBean, new PropertyUtilsBean());
0126:            }
0127:
0128:            /** 
0129:             * <p>Constructs an instance using given property and conversion instances.</p>
0130:             *
0131:             * @param convertUtilsBean use this <code>ConvertUtilsBean</code> 
0132:             * to perform conversions from one object to another
0133:             * @param propertyUtilsBean use this <code>PropertyUtilsBean</code>
0134:             * to access properties
0135:             */
0136:            public BeanUtilsBean(ConvertUtilsBean convertUtilsBean,
0137:                    PropertyUtilsBean propertyUtilsBean) {
0138:
0139:                this .convertUtilsBean = convertUtilsBean;
0140:                this .propertyUtilsBean = propertyUtilsBean;
0141:            }
0142:
0143:            // --------------------------------------------------------- Public Methods
0144:
0145:            /**
0146:             * <p>Clone a bean based on the available property getters and setters,
0147:             * even if the bean class itself does not implement Cloneable.</p>
0148:             *
0149:             * <p>
0150:             * <strong>Note:</strong> this method creates a <strong>shallow</strong> clone.
0151:             * In other words, any objects referred to by the bean are shared with the clone
0152:             * rather than being cloned in turn.
0153:             * </p>
0154:             *
0155:             * @param bean Bean to be cloned
0156:             * @return the cloned bean
0157:             *
0158:             * @exception IllegalAccessException if the caller does not have
0159:             *  access to the property accessor method
0160:             * @exception InstantiationException if a new instance of the bean's
0161:             *  class cannot be instantiated
0162:             * @exception InvocationTargetException if the property accessor method
0163:             *  throws an exception
0164:             * @exception NoSuchMethodException if an accessor method for this
0165:             *  property cannot be found
0166:             */
0167:            public Object cloneBean(Object bean) throws IllegalAccessException,
0168:                    InstantiationException, InvocationTargetException,
0169:                    NoSuchMethodException {
0170:
0171:                if (log.isDebugEnabled()) {
0172:                    log.debug("Cloning bean: " + bean.getClass().getName());
0173:                }
0174:                Object newBean = null;
0175:                if (bean instanceof  DynaBean) {
0176:                    newBean = ((DynaBean) bean).getDynaClass().newInstance();
0177:                } else {
0178:                    newBean = bean.getClass().newInstance();
0179:                }
0180:                getPropertyUtils().copyProperties(newBean, bean);
0181:                return (newBean);
0182:
0183:            }
0184:
0185:            /**
0186:             * <p>Copy property values from the origin bean to the destination bean
0187:             * for all cases where the property names are the same.  For each
0188:             * property, a conversion is attempted as necessary.  All combinations of
0189:             * standard JavaBeans and DynaBeans as origin and destination are
0190:             * supported.  Properties that exist in the origin bean, but do not exist
0191:             * in the destination bean (or are read-only in the destination bean) are
0192:             * silently ignored.</p>
0193:             *
0194:             * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed
0195:             * to contain String-valued <strong>simple</strong> property names as the keys, pointing at
0196:             * the corresponding property values that will be converted (if necessary)
0197:             * and set in the destination bean. <strong>Note</strong> that this method
0198:             * is intended to perform a "shallow copy" of the properties and so complex
0199:             * properties (for example, nested ones) will not be copied.</p>
0200:             *
0201:             * <p>This method differs from <code>populate()</code>, which
0202:             * was primarily designed for populating JavaBeans from the map of request
0203:             * parameters retrieved on an HTTP request, is that no scalar->indexed
0204:             * or indexed->scalar manipulations are performed.  If the origin property
0205:             * is indexed, the destination property must be also.</p>
0206:             *
0207:             * <p>If you know that no type conversions are required, the
0208:             * <code>copyProperties()</code> method in {@link PropertyUtils} will
0209:             * execute faster than this method.</p>
0210:             *
0211:             * <p><strong>FIXME</strong> - Indexed and mapped properties that do not
0212:             * have getter and setter methods for the underlying array or Map are not
0213:             * copied by this method.</p>
0214:             *
0215:             * @param dest Destination bean whose properties are modified
0216:             * @param orig Origin bean whose properties are retrieved
0217:             *
0218:             * @exception IllegalAccessException if the caller does not have
0219:             *  access to the property accessor method
0220:             * @exception IllegalArgumentException if the <code>dest</code> or
0221:             *  <code>orig</code> argument is null or if the <code>dest</code> 
0222:             *  property type is different from the source type and the relevant
0223:             *  converter has not been registered.
0224:             * @exception InvocationTargetException if the property accessor method
0225:             *  throws an exception
0226:             */
0227:            public void copyProperties(Object dest, Object orig)
0228:                    throws IllegalAccessException, InvocationTargetException {
0229:
0230:                // Validate existence of the specified beans
0231:                if (dest == null) {
0232:                    throw new IllegalArgumentException(
0233:                            "No destination bean specified");
0234:                }
0235:                if (orig == null) {
0236:                    throw new IllegalArgumentException(
0237:                            "No origin bean specified");
0238:                }
0239:                if (log.isDebugEnabled()) {
0240:                    log.debug("BeanUtils.copyProperties(" + dest + ", " + orig
0241:                            + ")");
0242:                }
0243:
0244:                // Copy the properties, converting as necessary
0245:                if (orig instanceof  DynaBean) {
0246:                    DynaProperty[] origDescriptors = ((DynaBean) orig)
0247:                            .getDynaClass().getDynaProperties();
0248:                    for (int i = 0; i < origDescriptors.length; i++) {
0249:                        String name = origDescriptors[i].getName();
0250:                        // Need to check isReadable() for WrapDynaBean
0251:                        // (see Jira issue# BEANUTILS-61)
0252:                        if (getPropertyUtils().isReadable(orig, name)
0253:                                && getPropertyUtils().isWriteable(dest, name)) {
0254:                            Object value = ((DynaBean) orig).get(name);
0255:                            copyProperty(dest, name, value);
0256:                        }
0257:                    }
0258:                } else if (orig instanceof  Map) {
0259:                    Iterator names = ((Map) orig).keySet().iterator();
0260:                    while (names.hasNext()) {
0261:                        String name = (String) names.next();
0262:                        if (getPropertyUtils().isWriteable(dest, name)) {
0263:                            Object value = ((Map) orig).get(name);
0264:                            copyProperty(dest, name, value);
0265:                        }
0266:                    }
0267:                } else /* if (orig is a standard JavaBean) */{
0268:                    PropertyDescriptor[] origDescriptors = getPropertyUtils()
0269:                            .getPropertyDescriptors(orig);
0270:                    for (int i = 0; i < origDescriptors.length; i++) {
0271:                        String name = origDescriptors[i].getName();
0272:                        if ("class".equals(name)) {
0273:                            continue; // No point in trying to set an object's class
0274:                        }
0275:                        if (getPropertyUtils().isReadable(orig, name)
0276:                                && getPropertyUtils().isWriteable(dest, name)) {
0277:                            try {
0278:                                Object value = getPropertyUtils()
0279:                                        .getSimpleProperty(orig, name);
0280:                                copyProperty(dest, name, value);
0281:                            } catch (NoSuchMethodException e) {
0282:                                // Should not happen
0283:                            }
0284:                        }
0285:                    }
0286:                }
0287:
0288:            }
0289:
0290:            /**
0291:             * <p>Copy the specified property value to the specified destination bean,
0292:             * performing any type conversion that is required.  If the specified
0293:             * bean does not have a property of the specified name, or the property
0294:             * is read only on the destination bean, return without
0295:             * doing anything.  If you have custom destination property types, register
0296:             * {@link Converter}s for them by calling the <code>register()</code>
0297:             * method of {@link ConvertUtils}.</p>
0298:             *
0299:             * <p><strong>IMPLEMENTATION RESTRICTIONS</strong>:</p>
0300:             * <ul>
0301:             * <li>Does not support destination properties that are indexed,
0302:             *     but only an indexed setter (as opposed to an array setter)
0303:             *     is available.</li>
0304:             * <li>Does not support destination properties that are mapped,
0305:             *     but only a keyed setter (as opposed to a Map setter)
0306:             *     is available.</li>
0307:             * <li>The desired property type of a mapped setter cannot be
0308:             *     determined (since Maps support any data type), so no conversion
0309:             *     will be performed.</li>
0310:             * </ul>
0311:             *
0312:             * @param bean Bean on which setting is to be performed
0313:             * @param name Property name (can be nested/indexed/mapped/combo)
0314:             * @param value Value to be set
0315:             *
0316:             * @exception IllegalAccessException if the caller does not have
0317:             *  access to the property accessor method
0318:             * @exception InvocationTargetException if the property accessor method
0319:             *  throws an exception
0320:             */
0321:            public void copyProperty(Object bean, String name, Object value)
0322:                    throws IllegalAccessException, InvocationTargetException {
0323:
0324:                // Trace logging (if enabled)
0325:                if (log.isTraceEnabled()) {
0326:                    StringBuffer sb = new StringBuffer("  copyProperty(");
0327:                    sb.append(bean);
0328:                    sb.append(", ");
0329:                    sb.append(name);
0330:                    sb.append(", ");
0331:                    if (value == null) {
0332:                        sb.append("<NULL>");
0333:                    } else if (value instanceof  String) {
0334:                        sb.append((String) value);
0335:                    } else if (value instanceof  String[]) {
0336:                        String[] values = (String[]) value;
0337:                        sb.append('[');
0338:                        for (int i = 0; i < values.length; i++) {
0339:                            if (i > 0) {
0340:                                sb.append(',');
0341:                            }
0342:                            sb.append(values[i]);
0343:                        }
0344:                        sb.append(']');
0345:                    } else {
0346:                        sb.append(value.toString());
0347:                    }
0348:                    sb.append(')');
0349:                    log.trace(sb.toString());
0350:                }
0351:
0352:                // Resolve any nested expression to get the actual target bean
0353:                Object target = bean;
0354:                Resolver resolver = getPropertyUtils().getResolver();
0355:                while (resolver.hasNested(name)) {
0356:                    try {
0357:                        target = getPropertyUtils().getProperty(target,
0358:                                resolver.next(name));
0359:                        name = resolver.remove(name);
0360:                    } catch (NoSuchMethodException e) {
0361:                        return; // Skip this property setter
0362:                    }
0363:                }
0364:                if (log.isTraceEnabled()) {
0365:                    log.trace("    Target bean = " + target);
0366:                    log.trace("    Target name = " + name);
0367:                }
0368:
0369:                // Declare local variables we will require
0370:                String propName = resolver.getProperty(name); // Simple name of target property
0371:                Class type = null; // Java type of target property
0372:                int index = resolver.getIndex(name); // Indexed subscript value (if any)
0373:                String key = resolver.getKey(name); // Mapped key value (if any)
0374:
0375:                // Calculate the target property type
0376:                if (target instanceof  DynaBean) {
0377:                    DynaClass dynaClass = ((DynaBean) target).getDynaClass();
0378:                    DynaProperty dynaProperty = dynaClass
0379:                            .getDynaProperty(propName);
0380:                    if (dynaProperty == null) {
0381:                        return; // Skip this property setter
0382:                    }
0383:                    type = dynaProperty.getType();
0384:                } else {
0385:                    PropertyDescriptor descriptor = null;
0386:                    try {
0387:                        descriptor = getPropertyUtils().getPropertyDescriptor(
0388:                                target, name);
0389:                        if (descriptor == null) {
0390:                            return; // Skip this property setter
0391:                        }
0392:                    } catch (NoSuchMethodException e) {
0393:                        return; // Skip this property setter
0394:                    }
0395:                    type = descriptor.getPropertyType();
0396:                    if (type == null) {
0397:                        // Most likely an indexed setter on a POJB only
0398:                        if (log.isTraceEnabled()) {
0399:                            log.trace("    target type for property '"
0400:                                    + propName
0401:                                    + "' is null, so skipping ths setter");
0402:                        }
0403:                        return;
0404:                    }
0405:                }
0406:                if (log.isTraceEnabled()) {
0407:                    log.trace("    target propName=" + propName + ", type="
0408:                            + type + ", index=" + index + ", key=" + key);
0409:                }
0410:
0411:                // Convert the specified value to the required type and store it
0412:                if (index >= 0) { // Destination must be indexed
0413:                    value = convert(value, type.getComponentType());
0414:                    try {
0415:                        getPropertyUtils().setIndexedProperty(target, propName,
0416:                                index, value);
0417:                    } catch (NoSuchMethodException e) {
0418:                        throw new InvocationTargetException(e, "Cannot set "
0419:                                + propName);
0420:                    }
0421:                } else if (key != null) { // Destination must be mapped
0422:                    // Maps do not know what the preferred data type is,
0423:                    // so perform no conversions at all
0424:                    // FIXME - should we create or support a TypedMap?
0425:                    try {
0426:                        getPropertyUtils().setMappedProperty(target, propName,
0427:                                key, value);
0428:                    } catch (NoSuchMethodException e) {
0429:                        throw new InvocationTargetException(e, "Cannot set "
0430:                                + propName);
0431:                    }
0432:                } else { // Destination must be simple
0433:                    value = convert(value, type);
0434:                    try {
0435:                        getPropertyUtils().setSimpleProperty(target, propName,
0436:                                value);
0437:                    } catch (NoSuchMethodException e) {
0438:                        throw new InvocationTargetException(e, "Cannot set "
0439:                                + propName);
0440:                    }
0441:                }
0442:
0443:            }
0444:
0445:            /**
0446:             * <p>Return the entire set of properties for which the specified bean
0447:             * provides a read method. This map contains the to <code>String</code>
0448:             * converted property values for all properties for which a read method
0449:             * is provided (i.e. where the getReadMethod() returns non-null).</p>
0450:             *
0451:             * <p>This map can be fed back to a call to
0452:             * <code>BeanUtils.populate()</code> to reconsitute the same set of
0453:             * properties, modulo differences for read-only and write-only
0454:             * properties, but only if there are no indexed properties.</p>
0455:             *
0456:             * <p><strong>Warning:</strong> if any of the bean property implementations
0457:             * contain (directly or indirectly) a call to this method then 
0458:             * a stack overflow may result. For example:
0459:             * <code><pre>
0460:             * class MyBean
0461:             * {
0462:             *    public Map getParameterMap()
0463:             *    {
0464:             *         BeanUtils.describe(this);
0465:             *    }
0466:             * }
0467:             * </pre></code>
0468:             * will result in an infinite regression when <code>getParametersMap</code>
0469:             * is called. It is recommended that such methods are given alternative
0470:             * names (for example, <code>parametersMap</code>).
0471:             * </p>
0472:             * @param bean Bean whose properties are to be extracted
0473:             * @return Map of property descriptors
0474:             *
0475:             * @exception IllegalAccessException if the caller does not have
0476:             *  access to the property accessor method
0477:             * @exception InvocationTargetException if the property accessor method
0478:             *  throws an exception
0479:             * @exception NoSuchMethodException if an accessor method for this
0480:             *  property cannot be found
0481:             */
0482:            public Map describe(Object bean) throws IllegalAccessException,
0483:                    InvocationTargetException, NoSuchMethodException {
0484:
0485:                if (bean == null) {
0486:                    //            return (Collections.EMPTY_MAP);
0487:                    return (new java.util.HashMap());
0488:                }
0489:
0490:                if (log.isDebugEnabled()) {
0491:                    log.debug("Describing bean: " + bean.getClass().getName());
0492:                }
0493:
0494:                Map description = new HashMap();
0495:                if (bean instanceof  DynaBean) {
0496:                    DynaProperty[] descriptors = ((DynaBean) bean)
0497:                            .getDynaClass().getDynaProperties();
0498:                    for (int i = 0; i < descriptors.length; i++) {
0499:                        String name = descriptors[i].getName();
0500:                        description.put(name, getProperty(bean, name));
0501:                    }
0502:                } else {
0503:                    PropertyDescriptor[] descriptors = getPropertyUtils()
0504:                            .getPropertyDescriptors(bean);
0505:                    for (int i = 0; i < descriptors.length; i++) {
0506:                        String name = descriptors[i].getName();
0507:                        if (getPropertyUtils().getReadMethod(descriptors[i]) != null) {
0508:                            description.put(name, getProperty(bean, name));
0509:                        }
0510:                    }
0511:                }
0512:                return (description);
0513:
0514:            }
0515:
0516:            /**
0517:             * Return the value of the specified array property of the specified
0518:             * bean, as a String array.
0519:             *
0520:             * @param bean Bean whose property is to be extracted
0521:             * @param name Name of the property to be extracted
0522:             * @return The array property value
0523:             *
0524:             * @exception IllegalAccessException if the caller does not have
0525:             *  access to the property accessor method
0526:             * @exception InvocationTargetException if the property accessor method
0527:             *  throws an exception
0528:             * @exception NoSuchMethodException if an accessor method for this
0529:             *  property cannot be found
0530:             */
0531:            public String[] getArrayProperty(Object bean, String name)
0532:                    throws IllegalAccessException, InvocationTargetException,
0533:                    NoSuchMethodException {
0534:
0535:                Object value = getPropertyUtils().getProperty(bean, name);
0536:                if (value == null) {
0537:                    return (null);
0538:                } else if (value instanceof  Collection) {
0539:                    ArrayList values = new ArrayList();
0540:                    Iterator items = ((Collection) value).iterator();
0541:                    while (items.hasNext()) {
0542:                        Object item = items.next();
0543:                        if (item == null) {
0544:                            values.add((String) null);
0545:                        } else {
0546:                            // convert to string using convert utils
0547:                            values.add(getConvertUtils().convert(item));
0548:                        }
0549:                    }
0550:                    return ((String[]) values
0551:                            .toArray(new String[values.size()]));
0552:                } else if (value.getClass().isArray()) {
0553:                    int n = Array.getLength(value);
0554:                    String[] results = new String[n];
0555:                    for (int i = 0; i < n; i++) {
0556:                        Object item = Array.get(value, i);
0557:                        if (item == null) {
0558:                            results[i] = null;
0559:                        } else {
0560:                            // convert to string using convert utils
0561:                            results[i] = getConvertUtils().convert(item);
0562:                        }
0563:                    }
0564:                    return (results);
0565:                } else {
0566:                    String[] results = new String[1];
0567:                    results[0] = getConvertUtils().convert(value);
0568:                    return (results);
0569:                }
0570:
0571:            }
0572:
0573:            /**
0574:             * Return the value of the specified indexed property of the specified
0575:             * bean, as a String.  The zero-relative index of the
0576:             * required value must be included (in square brackets) as a suffix to
0577:             * the property name, or <code>IllegalArgumentException</code> will be
0578:             * thrown.
0579:             *
0580:             * @param bean Bean whose property is to be extracted
0581:             * @param name <code>propertyname[index]</code> of the property value
0582:             *  to be extracted
0583:             * @return The indexed property's value, converted to a String
0584:             *
0585:             * @exception IllegalAccessException if the caller does not have
0586:             *  access to the property accessor method
0587:             * @exception InvocationTargetException if the property accessor method
0588:             *  throws an exception
0589:             * @exception NoSuchMethodException if an accessor method for this
0590:             *  property cannot be found
0591:             */
0592:            public String getIndexedProperty(Object bean, String name)
0593:                    throws IllegalAccessException, InvocationTargetException,
0594:                    NoSuchMethodException {
0595:
0596:                Object value = getPropertyUtils()
0597:                        .getIndexedProperty(bean, name);
0598:                return (getConvertUtils().convert(value));
0599:
0600:            }
0601:
0602:            /**
0603:             * Return the value of the specified indexed property of the specified
0604:             * bean, as a String.  The index is specified as a method parameter and
0605:             * must *not* be included in the property name expression
0606:             *
0607:             * @param bean Bean whose property is to be extracted
0608:             * @param name Simple property name of the property value to be extracted
0609:             * @param index Index of the property value to be extracted
0610:             * @return The indexed property's value, converted to a String
0611:             *
0612:             * @exception IllegalAccessException if the caller does not have
0613:             *  access to the property accessor method
0614:             * @exception InvocationTargetException if the property accessor method
0615:             *  throws an exception
0616:             * @exception NoSuchMethodException if an accessor method for this
0617:             *  property cannot be found
0618:             */
0619:            public String getIndexedProperty(Object bean, String name, int index)
0620:                    throws IllegalAccessException, InvocationTargetException,
0621:                    NoSuchMethodException {
0622:
0623:                Object value = getPropertyUtils().getIndexedProperty(bean,
0624:                        name, index);
0625:                return (getConvertUtils().convert(value));
0626:
0627:            }
0628:
0629:            /**
0630:             * Return the value of the specified indexed property of the specified
0631:             * bean, as a String.  The String-valued key of the required value
0632:             * must be included (in parentheses) as a suffix to
0633:             * the property name, or <code>IllegalArgumentException</code> will be
0634:             * thrown.
0635:             *
0636:             * @param bean Bean whose property is to be extracted
0637:             * @param name <code>propertyname(index)</code> of the property value
0638:             *  to be extracted
0639:             * @return The mapped property's value, converted to a String
0640:             *
0641:             * @exception IllegalAccessException if the caller does not have
0642:             *  access to the property accessor method
0643:             * @exception InvocationTargetException if the property accessor method
0644:             *  throws an exception
0645:             * @exception NoSuchMethodException if an accessor method for this
0646:             *  property cannot be found
0647:             */
0648:            public String getMappedProperty(Object bean, String name)
0649:                    throws IllegalAccessException, InvocationTargetException,
0650:                    NoSuchMethodException {
0651:
0652:                Object value = getPropertyUtils().getMappedProperty(bean, name);
0653:                return (getConvertUtils().convert(value));
0654:
0655:            }
0656:
0657:            /**
0658:             * Return the value of the specified mapped property of the specified
0659:             * bean, as a String.  The key is specified as a method parameter and
0660:             * must *not* be included in the property name expression
0661:             *
0662:             * @param bean Bean whose property is to be extracted
0663:             * @param name Simple property name of the property value to be extracted
0664:             * @param key Lookup key of the property value to be extracted
0665:             * @return The mapped property's value, converted to a String
0666:             *
0667:             * @exception IllegalAccessException if the caller does not have
0668:             *  access to the property accessor method
0669:             * @exception InvocationTargetException if the property accessor method
0670:             *  throws an exception
0671:             * @exception NoSuchMethodException if an accessor method for this
0672:             *  property cannot be found
0673:             */
0674:            public String getMappedProperty(Object bean, String name, String key)
0675:                    throws IllegalAccessException, InvocationTargetException,
0676:                    NoSuchMethodException {
0677:
0678:                Object value = getPropertyUtils().getMappedProperty(bean, name,
0679:                        key);
0680:                return (getConvertUtils().convert(value));
0681:
0682:            }
0683:
0684:            /**
0685:             * Return the value of the (possibly nested) property of the specified
0686:             * name, for the specified bean, as a String.
0687:             *
0688:             * @param bean Bean whose property is to be extracted
0689:             * @param name Possibly nested name of the property to be extracted
0690:             * @return The nested property's value, converted to a String
0691:             *
0692:             * @exception IllegalAccessException if the caller does not have
0693:             *  access to the property accessor method
0694:             * @exception IllegalArgumentException if a nested reference to a
0695:             *  property returns null
0696:             * @exception InvocationTargetException if the property accessor method
0697:             *  throws an exception
0698:             * @exception NoSuchMethodException if an accessor method for this
0699:             *  property cannot be found
0700:             */
0701:            public String getNestedProperty(Object bean, String name)
0702:                    throws IllegalAccessException, InvocationTargetException,
0703:                    NoSuchMethodException {
0704:
0705:                Object value = getPropertyUtils().getNestedProperty(bean, name);
0706:                return (getConvertUtils().convert(value));
0707:
0708:            }
0709:
0710:            /**
0711:             * Return the value of the specified property of the specified bean,
0712:             * no matter which property reference format is used, as a String.
0713:             *
0714:             * @param bean Bean whose property is to be extracted
0715:             * @param name Possibly indexed and/or nested name of the property
0716:             *  to be extracted
0717:             * @return The property's value, converted to a String
0718:             *
0719:             * @exception IllegalAccessException if the caller does not have
0720:             *  access to the property accessor method
0721:             * @exception InvocationTargetException if the property accessor method
0722:             *  throws an exception
0723:             * @exception NoSuchMethodException if an accessor method for this
0724:             *  property cannot be found
0725:             */
0726:            public String getProperty(Object bean, String name)
0727:                    throws IllegalAccessException, InvocationTargetException,
0728:                    NoSuchMethodException {
0729:
0730:                return (getNestedProperty(bean, name));
0731:
0732:            }
0733:
0734:            /**
0735:             * Return the value of the specified simple property of the specified
0736:             * bean, converted to a String.
0737:             *
0738:             * @param bean Bean whose property is to be extracted
0739:             * @param name Name of the property to be extracted
0740:             * @return The property's value, converted to a String
0741:             *
0742:             * @exception IllegalAccessException if the caller does not have
0743:             *  access to the property accessor method
0744:             * @exception InvocationTargetException if the property accessor method
0745:             *  throws an exception
0746:             * @exception NoSuchMethodException if an accessor method for this
0747:             *  property cannot be found
0748:             */
0749:            public String getSimpleProperty(Object bean, String name)
0750:                    throws IllegalAccessException, InvocationTargetException,
0751:                    NoSuchMethodException {
0752:
0753:                Object value = getPropertyUtils().getSimpleProperty(bean, name);
0754:                return (getConvertUtils().convert(value));
0755:
0756:            }
0757:
0758:            /**
0759:             * <p>Populate the JavaBeans properties of the specified bean, based on
0760:             * the specified name/value pairs.  This method uses Java reflection APIs
0761:             * to identify corresponding "property setter" method names, and deals
0762:             * with setter arguments of type <code>String</code>, <code>boolean</code>,
0763:             * <code>int</code>, <code>long</code>, <code>float</code>, and
0764:             * <code>double</code>.  In addition, array setters for these types (or the
0765:             * corresponding primitive types) can also be identified.</p>
0766:             * 
0767:             * <p>The particular setter method to be called for each property is
0768:             * determined using the usual JavaBeans introspection mechanisms.  Thus,
0769:             * you may identify custom setter methods using a BeanInfo class that is
0770:             * associated with the class of the bean itself.  If no such BeanInfo
0771:             * class is available, the standard method name conversion ("set" plus
0772:             * the capitalized name of the property in question) is used.</p>
0773:             * 
0774:             * <p><strong>NOTE</strong>:  It is contrary to the JavaBeans Specification
0775:             * to have more than one setter method (with different argument
0776:             * signatures) for the same property.</p>
0777:             *
0778:             * <p><strong>WARNING</strong> - The logic of this method is customized
0779:             * for extracting String-based request parameters from an HTTP request.
0780:             * It is probably not what you want for general property copying with
0781:             * type conversion.  For that purpose, check out the
0782:             * <code>copyProperties()</code> method instead.</p>
0783:             *
0784:             * @param bean JavaBean whose properties are being populated
0785:             * @param properties Map keyed by property name, with the
0786:             *  corresponding (String or String[]) value(s) to be set
0787:             *
0788:             * @exception IllegalAccessException if the caller does not have
0789:             *  access to the property accessor method
0790:             * @exception InvocationTargetException if the property accessor method
0791:             *  throws an exception
0792:             */
0793:            public void populate(Object bean, Map properties)
0794:                    throws IllegalAccessException, InvocationTargetException {
0795:
0796:                // Do nothing unless both arguments have been specified
0797:                if ((bean == null) || (properties == null)) {
0798:                    return;
0799:                }
0800:                if (log.isDebugEnabled()) {
0801:                    log.debug("BeanUtils.populate(" + bean + ", " + properties
0802:                            + ")");
0803:                }
0804:
0805:                // Loop through the property name/value pairs to be set
0806:                Iterator names = properties.keySet().iterator();
0807:                while (names.hasNext()) {
0808:
0809:                    // Identify the property name and value(s) to be assigned
0810:                    String name = (String) names.next();
0811:                    if (name == null) {
0812:                        continue;
0813:                    }
0814:                    Object value = properties.get(name);
0815:
0816:                    // Perform the assignment for this property
0817:                    setProperty(bean, name, value);
0818:
0819:                }
0820:
0821:            }
0822:
0823:            /**
0824:             * <p>Set the specified property value, performing type conversions as
0825:             * required to conform to the type of the destination property.</p>
0826:             *
0827:             * <p>If the property is read only then the method returns 
0828:             * without throwing an exception.</p>
0829:             *
0830:             * <p>If <code>null</code> is passed into a property expecting a primitive value,
0831:             * then this will be converted as if it were a <code>null</code> string.</p>
0832:             *
0833:             * <p><strong>WARNING</strong> - The logic of this method is customized
0834:             * to meet the needs of <code>populate()</code>, and is probably not what
0835:             * you want for general property copying with type conversion.  For that
0836:             * purpose, check out the <code>copyProperty()</code> method instead.</p>
0837:             *
0838:             * <p><strong>WARNING</strong> - PLEASE do not modify the behavior of this
0839:             * method without consulting with the Struts developer community.  There
0840:             * are some subtleties to its functionality that are not documented in the
0841:             * Javadoc description above, yet are vital to the way that Struts utilizes
0842:             * this method.</p>
0843:             *
0844:             * @param bean Bean on which setting is to be performed
0845:             * @param name Property name (can be nested/indexed/mapped/combo)
0846:             * @param value Value to be set
0847:             *
0848:             * @exception IllegalAccessException if the caller does not have
0849:             *  access to the property accessor method
0850:             * @exception InvocationTargetException if the property accessor method
0851:             *  throws an exception
0852:             */
0853:            public void setProperty(Object bean, String name, Object value)
0854:                    throws IllegalAccessException, InvocationTargetException {
0855:
0856:                // Trace logging (if enabled)
0857:                if (log.isTraceEnabled()) {
0858:                    StringBuffer sb = new StringBuffer("  setProperty(");
0859:                    sb.append(bean);
0860:                    sb.append(", ");
0861:                    sb.append(name);
0862:                    sb.append(", ");
0863:                    if (value == null) {
0864:                        sb.append("<NULL>");
0865:                    } else if (value instanceof  String) {
0866:                        sb.append((String) value);
0867:                    } else if (value instanceof  String[]) {
0868:                        String[] values = (String[]) value;
0869:                        sb.append('[');
0870:                        for (int i = 0; i < values.length; i++) {
0871:                            if (i > 0) {
0872:                                sb.append(',');
0873:                            }
0874:                            sb.append(values[i]);
0875:                        }
0876:                        sb.append(']');
0877:                    } else {
0878:                        sb.append(value.toString());
0879:                    }
0880:                    sb.append(')');
0881:                    log.trace(sb.toString());
0882:                }
0883:
0884:                // Resolve any nested expression to get the actual target bean
0885:                Object target = bean;
0886:                Resolver resolver = getPropertyUtils().getResolver();
0887:                while (resolver.hasNested(name)) {
0888:                    try {
0889:                        target = getPropertyUtils().getProperty(target,
0890:                                resolver.next(name));
0891:                        name = resolver.remove(name);
0892:                    } catch (NoSuchMethodException e) {
0893:                        return; // Skip this property setter
0894:                    }
0895:                }
0896:                if (log.isTraceEnabled()) {
0897:                    log.trace("    Target bean = " + target);
0898:                    log.trace("    Target name = " + name);
0899:                }
0900:
0901:                // Declare local variables we will require
0902:                String propName = resolver.getProperty(name); // Simple name of target property
0903:                Class type = null; // Java type of target property
0904:                int index = resolver.getIndex(name); // Indexed subscript value (if any)
0905:                String key = resolver.getKey(name); // Mapped key value (if any)
0906:
0907:                // Calculate the property type
0908:                if (target instanceof  DynaBean) {
0909:                    DynaClass dynaClass = ((DynaBean) target).getDynaClass();
0910:                    DynaProperty dynaProperty = dynaClass
0911:                            .getDynaProperty(propName);
0912:                    if (dynaProperty == null) {
0913:                        return; // Skip this property setter
0914:                    }
0915:                    type = dynaProperty.getType();
0916:                } else {
0917:                    PropertyDescriptor descriptor = null;
0918:                    try {
0919:                        descriptor = getPropertyUtils().getPropertyDescriptor(
0920:                                target, name);
0921:                        if (descriptor == null) {
0922:                            return; // Skip this property setter
0923:                        }
0924:                    } catch (NoSuchMethodException e) {
0925:                        return; // Skip this property setter
0926:                    }
0927:                    if (descriptor instanceof  MappedPropertyDescriptor) {
0928:                        if (((MappedPropertyDescriptor) descriptor)
0929:                                .getMappedWriteMethod() == null) {
0930:                            if (log.isDebugEnabled()) {
0931:                                log.debug("Skipping read-only property");
0932:                            }
0933:                            return; // Read-only, skip this property setter
0934:                        }
0935:                        type = ((MappedPropertyDescriptor) descriptor)
0936:                                .getMappedPropertyType();
0937:                    } else if (index >= 0
0938:                            && descriptor instanceof  IndexedPropertyDescriptor) {
0939:                        if (((IndexedPropertyDescriptor) descriptor)
0940:                                .getIndexedWriteMethod() == null) {
0941:                            if (log.isDebugEnabled()) {
0942:                                log.debug("Skipping read-only property");
0943:                            }
0944:                            return; // Read-only, skip this property setter
0945:                        }
0946:                        type = ((IndexedPropertyDescriptor) descriptor)
0947:                                .getIndexedPropertyType();
0948:                    } else if (key != null) {
0949:                        if (descriptor.getReadMethod() == null) {
0950:                            if (log.isDebugEnabled()) {
0951:                                log.debug("Skipping read-only property");
0952:                            }
0953:                            return; // Read-only, skip this property setter
0954:                        }
0955:                        type = (value == null) ? Object.class : value
0956:                                .getClass();
0957:                    } else {
0958:                        if (descriptor.getWriteMethod() == null) {
0959:                            if (log.isDebugEnabled()) {
0960:                                log.debug("Skipping read-only property");
0961:                            }
0962:                            return; // Read-only, skip this property setter
0963:                        }
0964:                        type = descriptor.getPropertyType();
0965:                    }
0966:                }
0967:
0968:                // Convert the specified value to the required type
0969:                Object newValue = null;
0970:                if (type.isArray() && (index < 0)) { // Scalar value into array
0971:                    if (value == null) {
0972:                        String[] values = new String[1];
0973:                        values[0] = (String) value;
0974:                        newValue = getConvertUtils().convert((String[]) values,
0975:                                type);
0976:                    } else if (value instanceof  String) {
0977:                        newValue = getConvertUtils().convert(value, type);
0978:                    } else if (value instanceof  String[]) {
0979:                        newValue = getConvertUtils().convert((String[]) value,
0980:                                type);
0981:                    } else {
0982:                        newValue = convert(value, type);
0983:                    }
0984:                } else if (type.isArray()) { // Indexed value into array
0985:                    if (value instanceof  String || value == null) {
0986:                        newValue = getConvertUtils().convert((String) value,
0987:                                type.getComponentType());
0988:                    } else if (value instanceof  String[]) {
0989:                        newValue = getConvertUtils().convert(
0990:                                ((String[]) value)[0], type.getComponentType());
0991:                    } else {
0992:                        newValue = convert(value, type.getComponentType());
0993:                    }
0994:                } else { // Value into scalar
0995:                    if ((value instanceof  String) || (value == null)) {
0996:                        newValue = getConvertUtils().convert((String) value,
0997:                                type);
0998:                    } else if (value instanceof  String[]) {
0999:                        newValue = getConvertUtils().convert(
1000:                                ((String[]) value)[0], type);
1001:                    } else {
1002:                        newValue = convert(value, type);
1003:                    }
1004:                }
1005:
1006:                // Invoke the setter method
1007:                try {
1008:                    if (index >= 0) {
1009:                        getPropertyUtils().setIndexedProperty(target, propName,
1010:                                index, newValue);
1011:                    } else if (key != null) {
1012:                        getPropertyUtils().setMappedProperty(target, propName,
1013:                                key, newValue);
1014:                    } else {
1015:                        getPropertyUtils().setProperty(target, propName,
1016:                                newValue);
1017:                    }
1018:                } catch (NoSuchMethodException e) {
1019:                    throw new InvocationTargetException(e, "Cannot set "
1020:                            + propName);
1021:                }
1022:
1023:            }
1024:
1025:            /** 
1026:             * Gets the <code>ConvertUtilsBean</code> instance used to perform the conversions.
1027:             *
1028:             * @return The ConvertUtils bean instance
1029:             */
1030:            public ConvertUtilsBean getConvertUtils() {
1031:                return convertUtilsBean;
1032:            }
1033:
1034:            /**
1035:             * Gets the <code>PropertyUtilsBean</code> instance used to access properties.
1036:             *
1037:             * @return The ConvertUtils bean instance
1038:             */
1039:            public PropertyUtilsBean getPropertyUtils() {
1040:                return propertyUtilsBean;
1041:            }
1042:
1043:            /** 
1044:             * If we're running on JDK 1.4 or later, initialize the cause for the given throwable.
1045:             * 
1046:             * @param  throwable The throwable.
1047:             * @param  cause     The cause of the throwable.
1048:             * @return  true if the cause was initialized, otherwise false.
1049:             */
1050:            public boolean initCause(Throwable throwable, Throwable cause) {
1051:                if (INIT_CAUSE_METHOD != null && cause != null) {
1052:                    try {
1053:                        INIT_CAUSE_METHOD.invoke(throwable,
1054:                                new Object[] { cause });
1055:                        return true;
1056:                    } catch (Throwable e) {
1057:                        return false; // can't initialize cause
1058:                    }
1059:                }
1060:                return false;
1061:            }
1062:
1063:            /**
1064:             * <p>Convert the value to an object of the specified class (if
1065:             * possible).</p>
1066:             *
1067:             * @param value Value to be converted (may be null)
1068:             * @param type Class of the value to be converted to
1069:             * @return The converted value
1070:             *
1071:             * @exception ConversionException if thrown by an underlying Converter
1072:             */
1073:            protected Object convert(Object value, Class type) {
1074:                Converter converter = getConvertUtils().lookup(type);
1075:                if (converter != null) {
1076:                    log.trace("        USING CONVERTER " + converter);
1077:                    return converter.convert(type, value);
1078:                } else {
1079:                    return value;
1080:                }
1081:            }
1082:
1083:            /**
1084:             * Returns a <code>Method<code> allowing access to
1085:             * {@link Throwable#initCause(Throwable)} method of {@link Throwable},
1086:             * or <code>null</code> if the method
1087:             * does not exist.
1088:             * 
1089:             * @return A <code>Method<code> for <code>Throwable.initCause</code>, or
1090:             * <code>null</code> if unavailable.
1091:             */
1092:            private static Method getInitCauseMethod() {
1093:                try {
1094:                    Class[] paramsClasses = new Class[] { Throwable.class };
1095:                    return Throwable.class
1096:                            .getMethod("initCause", paramsClasses);
1097:                } catch (NoSuchMethodException e) {
1098:                    Log log = LogFactory.getLog(BeanUtils.class);
1099:                    if (log.isWarnEnabled()) {
1100:                        log
1101:                                .warn("Throwable does not have initCause() method in JDK 1.3");
1102:                    }
1103:                    return null;
1104:                } catch (Throwable e) {
1105:                    Log log = LogFactory.getLog(BeanUtils.class);
1106:                    if (log.isWarnEnabled()) {
1107:                        log
1108:                                .warn(
1109:                                        "Error getting the Throwable initCause() method",
1110:                                        e);
1111:                    }
1112:                    return null;
1113:                }
1114:            }
1115:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.