View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.commons.beanutils.locale;
    19
    20
    21  import org.apache.commons.beanutils.BeanUtilsBean;
    22  import org.apache.commons.beanutils.ConvertUtils;
    23  import org.apache.commons.beanutils.ConvertUtilsBean;
    24  import org.apache.commons.beanutils.DynaBean;
    25  import org.apache.commons.beanutils.DynaClass;
    26  import org.apache.commons.beanutils.DynaProperty;
    27  import org.apache.commons.beanutils.MappedPropertyDescriptor;
    28  import org.apache.commons.beanutils.PropertyUtilsBean;
    29  import org.apache.commons.beanutils.ContextClassLoaderLocal;
    30  import org.apache.commons.beanutils.expression.Resolver;
    31  import org.apache.commons.logging.Log;
    32  import org.apache.commons.logging.LogFactory;
    33
    34  import java.beans.IndexedPropertyDescriptor;
    35  import java.beans.PropertyDescriptor;
    36  import java.lang.reflect.InvocationTargetException;
    37  import java.util.Locale;
    38
    39
    40  /***
    41   * <p>Utility methods for populating JavaBeans properties
    42   * via reflection in a locale-dependent manner.</p>
    43   *
    44   * @author Craig R. McClanahan
    45   * @author Ralph Schaer
    46   * @author Chris Audley
    47   * @author Rey Francois
    48   * @author Gregor Rayman
    49   * @author Yauheny Mikulski
    50   * @since 1.7
    51   */
    52
    53  public class LocaleBeanUtilsBean extends BeanUtilsBean {
    54
    55      /***
    56       * Contains <code>LocaleBeanUtilsBean</code> instances indexed by context classloader.
    57       */
    58      private static final ContextClassLoaderLocal
    59              LOCALE_BEANS_BY_CLASSLOADER = new ContextClassLoaderLocal() {
    60                          // Creates the default instance used when the context classloader is unavailable
    61                          protected Object initialValue() {
    62                              return new LocaleBeanUtilsBean();
    63                          }
    64                      };
    65
    66       /***
    67        * Gets singleton instance
    68        *
    69        * @return the singleton instance
    70        */
    71       public static LocaleBeanUtilsBean getLocaleBeanUtilsInstance() {
    72          return (LocaleBeanUtilsBean)LOCALE_BEANS_BY_CLASSLOADER.get();
    73       }
    74
    75      /***
    76       * Sets the instance which provides the functionality for {@link LocaleBeanUtils}.
    77       * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
    78       * This mechanism provides isolation for web apps deployed in the same container.
    79       *
    80       * @param newInstance a new singleton instance
    81       */
    82      public static void setInstance(LocaleBeanUtilsBean newInstance) {
    83          LOCALE_BEANS_BY_CLASSLOADER.set(newInstance);
    84      }
    85
    86      /*** All logging goes through this logger */
    87      private Log log = LogFactory.getLog(LocaleBeanUtilsBean.class);
    88
    89      // ----------------------------------------------------- Instance Variables
    90
    91      /*** Convertor used by this class */
    92      private LocaleConvertUtilsBean localeConvertUtils;
    93
    94      // --------------------------------------------------------- Constructors
    95
    96      /*** Construct instance with standard conversion bean */
    97      public LocaleBeanUtilsBean() {
    98          this.localeConvertUtils = new LocaleConvertUtilsBean();
    99      }
    100
    101     /***
    102      * Construct instance that uses given locale conversion
    103      *
    104      * @param localeConvertUtils use this <code>localeConvertUtils</code> to perform
    105      * conversions
    106      * @param convertUtilsBean use this for standard conversions
    107      * @param propertyUtilsBean use this for property conversions
    108      */
    109     public LocaleBeanUtilsBean(
    110                             LocaleConvertUtilsBean localeConvertUtils,
    111                             ConvertUtilsBean convertUtilsBean,
    112                             PropertyUtilsBean propertyUtilsBean) {
    113         super(convertUtilsBean, propertyUtilsBean);
    114         this.localeConvertUtils = localeConvertUtils;
    115     }
    116
    117     /***
    118      * Construct instance that uses given locale conversion
    119      *
    120      * @param localeConvertUtils use this <code>localeConvertUtils</code> to perform
    121      * conversions
    122      */
    123     public LocaleBeanUtilsBean(LocaleConvertUtilsBean localeConvertUtils) {
    124         this.localeConvertUtils = localeConvertUtils;
    125     }
    126
    127     // --------------------------------------------------------- Public Methods
    128
    129     /***
    130      * Gets the bean instance used for conversions
    131      *
    132      * @return the locale converter bean instance
    133      */
    134     public LocaleConvertUtilsBean getLocaleConvertUtils() {
    135         return localeConvertUtils;
    136     }
    137
    138     /***
    139      * Gets the default Locale
    140      * @return the default locale
    141      */
    142     public Locale getDefaultLocale() {
    143
    144         return getLocaleConvertUtils().getDefaultLocale();
    145     }
    146
    147
    148     /***
    149      * Sets the default Locale.
    150      *
    151      * @param locale the default locale
    152      */
    153     public void setDefaultLocale(Locale locale) {
    154
    155         getLocaleConvertUtils().setDefaultLocale(locale);
    156     }
    157
    158     /***
    159      * Is the pattern to be applied localized
    160      * (Indicate whether the pattern is localized or not)
    161      *
    162      * @return <code>true</code> if pattern is localized,
    163      * otherwise <code>false</code>
    164      */
    165     public boolean getApplyLocalized() {
    166
    167         return getLocaleConvertUtils().getApplyLocalized();
    168     }
    169
    170     /***
    171      * Sets whether the pattern is applied localized
    172      * (Indicate whether the pattern is localized or not)
    173      *
    174      * @param newApplyLocalized <code>true</code> if pattern is localized,
    175      * otherwise <code>false</code>
    176      */
    177     public void setApplyLocalized(boolean newApplyLocalized) {
    178
    179         getLocaleConvertUtils().setApplyLocalized(newApplyLocalized);
    180     }
    181
    182
    183     // --------------------------------------------------------- Public Methods
    184
    185     /***
    186      * Return the value of the specified locale-sensitive indexed property
    187      * of the specified bean, as a String. The zero-relative index of the
    188      * required value must be included (in square brackets) as a suffix to
    189      * the property name, or <code>IllegalArgumentException</code> will be
    190      * thrown.
    191      *
    192      * @param bean Bean whose property is to be extracted
    193      * @param name <code>propertyname[index]</code> of the property value
    194      *  to be extracted
    195      * @param pattern The conversion pattern
    196      * @return The indexed property's value, converted to a String
    197      *
    198      * @exception IllegalAccessException if the caller does not have
    199      *  access to the property accessor method
    200      * @exception InvocationTargetException if the property accessor method
    201      *  throws an exception
    202      * @exception NoSuchMethodException if an accessor method for this
    203      *  propety cannot be found
    204      */
    205     public String getIndexedProperty(
    206                                     Object bean,
    207                                     String name,
    208                                     String pattern)
    209                                         throws
    210                                             IllegalAccessException,
    211                                             InvocationTargetException,
    212                                             NoSuchMethodException {
    213
    214         Object value = getPropertyUtils().getIndexedProperty(bean, name);
    215         return getLocaleConvertUtils().convert(value, pattern);
    216     }
    217
    218     /***
    219      * Return the value of the specified locale-sensitive indexed property
    220      * of the specified bean, as a String using the default conversion pattern of
    221      * the corresponding {@link LocaleConverter}. The zero-relative index
    222      * of the required value must be included (in square brackets) as a suffix
    223      * to the property name, or <code>IllegalArgumentException</code> will be thrown.
    224      *
    225      * @param bean Bean whose property is to be extracted
    226      * @param name <code>propertyname[index]</code> of the property value
    227      *  to be extracted
    228      * @return The indexed property's value, converted to a String
    229      *
    230      * @exception IllegalAccessException if the caller does not have
    231      *  access to the property accessor method
    232      * @exception InvocationTargetException if the property accessor method
    233      *  throws an exception
    234      * @exception NoSuchMethodException if an accessor method for this
    235      *  propety cannot be found
    236      */
    237     public String getIndexedProperty(
    238                                     Object bean,
    239                                     String name)
    240                                         throws
    241                                             IllegalAccessException,
    242                                             InvocationTargetException,
    243                                             NoSuchMethodException {
    244
    245         return getIndexedProperty(bean, name, null);
    246     }
    247
    248     /***
    249      * Return the value of the specified locale-sensetive indexed property
    250      * of the specified bean, as a String using the specified conversion pattern.
    251      * The index is specified as a method parameter and
    252      * must *not* be included in the property name expression
    253      *
    254      * @param bean Bean whose property is to be extracted
    255      * @param name Simple property name of the property value to be extracted
    256      * @param index Index of the property value to be extracted
    257      * @param pattern The conversion pattern
    258      * @return The indexed property's value, converted to a String
    259      *
    260      * @exception IllegalAccessException if the caller does not have
    261      *  access to the property accessor method
    262      * @exception InvocationTargetException if the property accessor method
    263      *  throws an exception
    264      * @exception NoSuchMethodException if an accessor method for this
    265      *  propety cannot be found
    266      */
    267     public String getIndexedProperty(Object bean,
    268                                             String name, int index, String pattern)
    269             throws IllegalAccessException, InvocationTargetException,
    270             NoSuchMethodException {
    271
    272         Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
    273         return getLocaleConvertUtils().convert(value, pattern);
    274     }
    275
    276     /***
    277      * Return the value of the specified locale-sensetive indexed property
    278      * of the specified bean, as a String using the default conversion pattern of
    279      * the corresponding {@link LocaleConverter}.
    280      * The index is specified as a method parameter and
    281      * must *not* be included in the property name expression
    282      *
    283      * @param bean Bean whose property is to be extracted
    284      * @param name Simple property name of the property value to be extracted
    285      * @param index Index of the property value to be extracted
    286      * @return The indexed property's value, converted to a String
    287      *
    288      * @exception IllegalAccessException if the caller does not have
    289      *  access to the property accessor method
    290      * @exception InvocationTargetException if the property accessor method
    291      *  throws an exception
    292      * @exception NoSuchMethodException if an accessor method for this
    293      *  propety cannot be found
    294      */
    295     public String getIndexedProperty(Object bean,
    296                                             String name, int index)
    297             throws IllegalAccessException, InvocationTargetException,
    298             NoSuchMethodException {
    299         return getIndexedProperty(bean, name, index, null);
    300     }
    301
    302     /***
    303      * Return the value of the specified simple locale-sensitive property
    304      * of the specified bean, converted to a String using the specified
    305      * conversion pattern.
    306      *
    307      * @param bean Bean whose property is to be extracted
    308      * @param name Name of the property to be extracted
    309      * @param pattern The conversion pattern
    310      * @return The property's value, converted to a String
    311      *
    312      * @exception IllegalAccessException if the caller does not have
    313      *  access to the property accessor method
    314      * @exception InvocationTargetException if the property accessor method
    315      *  throws an exception
    316      * @exception NoSuchMethodException if an accessor method for this
    317      *  propety cannot be found
    318      */
    319     public String getSimpleProperty(Object bean, String name, String pattern)
    320             throws IllegalAccessException, InvocationTargetException,
    321             NoSuchMethodException {
    322
    323         Object value = getPropertyUtils().getSimpleProperty(bean, name);
    324         return getLocaleConvertUtils().convert(value, pattern);
    325     }
    326
    327     /***
    328      * Return the value of the specified simple locale-sensitive property
    329      * of the specified bean, converted to a String using the default
    330      * conversion pattern of the corresponding {@link LocaleConverter}.
    331      *
    332      * @param bean Bean whose property is to be extracted
    333      * @param name Name of the property to be extracted
    334      * @return The property's value, converted to a String
    335      *
    336      * @exception IllegalAccessException if the caller does not have
    337      *  access to the property accessor method
    338      * @exception InvocationTargetException if the property accessor method
    339      *  throws an exception
    340      * @exception NoSuchMethodException if an accessor method for this
    341      *  propety cannot be found
    342      */
    343     public String getSimpleProperty(Object bean, String name)
    344             throws IllegalAccessException, InvocationTargetException,
    345             NoSuchMethodException {
    346
    347         return getSimpleProperty(bean, name, null);
    348     }
    349
    350     /***
    351      * Return the value of the specified mapped locale-sensitive property
    352      * of the specified bean, as a String using the specified conversion pattern.
    353      * The key is specified as a method parameter and must *not* be included in
    354      * the property name expression.
    355      *
    356      * @param bean Bean whose property is to be extracted
    357      * @param name Simple property name of the property value to be extracted
    358      * @param key Lookup key of the property value to be extracted
    359      * @param pattern The conversion pattern
    360      * @return The mapped property's value, converted to a String
    361      *
    362      * @exception IllegalAccessException if the caller does not have
    363      *  access to the property accessor method
    364      * @exception InvocationTargetException if the property accessor method
    365      *  throws an exception
    366      * @exception NoSuchMethodException if an accessor method for this
    367      *  propety cannot be found
    368      */
    369     public String getMappedProperty(
    370                                     Object bean,
    371                                     String name,
    372                                     String key,
    373                                     String pattern)
    374                                         throws
    375                                             IllegalAccessException,
    376                                             InvocationTargetException,
    377                                             NoSuchMethodException {
    378
    379         Object value = getPropertyUtils().getMappedProperty(bean, name, key);
    380         return getLocaleConvertUtils().convert(value, pattern);
    381     }
    382
    383     /***
    384      * Return the value of the specified mapped locale-sensitive property
    385      * of the specified bean, as a String
    386      * The key is specified as a method parameter and must *not* be included
    387      * in the property name expression
    388      *
    389      * @param bean Bean whose property is to be extracted
    390      * @param name Simple property name of the property value to be extracted
    391      * @param key Lookup key of the property value to be extracted
    392      * @return The mapped property's value, converted to a String
    393      *
    394      * @exception IllegalAccessException if the caller does not have
    395      *  access to the property accessor method
    396      * @exception InvocationTargetException if the property accessor method
    397      *  throws an exception
    398      * @exception NoSuchMethodException if an accessor method for this
    399      *  propety cannot be found
    400      */
    401     public String getMappedProperty(Object bean,
    402                                            String name, String key)
    403             throws IllegalAccessException, InvocationTargetException,
    404             NoSuchMethodException {
    405
    406         return getMappedProperty(bean, name, key, null);
    407     }
    408
    409
    410     /***
    411      * Return the value of the specified locale-sensitive mapped property
    412      * of the specified bean, as a String using the specified pattern.
    413      * The String-valued key of the required value
    414      * must be included (in parentheses) as a suffix to
    415      * the property name, or <code>IllegalArgumentException</code> will be
    416      * thrown.
    417      *
    418      * @param bean Bean whose property is to be extracted
    419      * @param name <code>propertyname(index)</code> of the property value
    420      *  to be extracted
    421      * @param pattern The conversion pattern
    422      * @return The mapped property's value, converted to a String
    423      *
    424      * @exception IllegalAccessException if the caller does not have
    425      *  access to the property accessor method
    426      * @exception InvocationTargetException if the property accessor method
    427      *  throws an exception
    428      * @exception NoSuchMethodException if an accessor method for this
    429      *  propety cannot be found
    430      */
    431     public String getMappedPropertyLocale(
    432                                         Object bean,
    433                                         String name,
    434                                         String pattern)
    435                                             throws
    436                                                 IllegalAccessException,
    437                                                 InvocationTargetException,
    438                                                 NoSuchMethodException {
    439
    440         Object value = getPropertyUtils().getMappedProperty(bean, name);
    441         return getLocaleConvertUtils().convert(value, pattern);
    442     }
    443
    444
    445     /***
    446      * Return the value of the specified locale-sensitive mapped property
    447      * of the specified bean, as a String using the default
    448      * conversion pattern of the corresponding {@link LocaleConverter}.
    449      * The String-valued key of the required value
    450      * must be included (in parentheses) as a suffix to
    451      * the property name, or <code>IllegalArgumentException</code> will be
    452      * thrown.
    453      *
    454      * @param bean Bean whose property is to be extracted
    455      * @param name <code>propertyname(index)</code> of the property value
    456      *  to be extracted
    457      * @return The mapped property's value, converted to a String
    458      *
    459      * @exception IllegalAccessException if the caller does not have
    460      *  access to the property accessor method
    461      * @exception InvocationTargetException if the property accessor method
    462      *  throws an exception
    463      * @exception NoSuchMethodException if an accessor method for this
    464      *  propety cannot be found
    465      */
    466     public String getMappedProperty(Object bean, String name)
    467                                     throws
    468                                         IllegalAccessException,
    469                                         InvocationTargetException,
    470                                         NoSuchMethodException {
    471
    472         return getMappedPropertyLocale(bean, name, null);
    473     }
    474
    475     /***
    476      * Return the value of the (possibly nested) locale-sensitive property
    477      * of the specified name, for the specified bean,
    478      * as a String using the specified pattern.
    479      *
    480      * @param bean Bean whose property is to be extracted
    481      * @param name Possibly nested name of the property to be extracted
    482      * @param pattern The conversion pattern
    483      * @return The nested property's value, converted to a String
    484      *
    485      * @exception IllegalAccessException if the caller does not have
    486      *  access to the property accessor method
    487      * @exception IllegalArgumentException if a nested reference to a
    488      *  property returns null
    489      * @exception InvocationTargetException if the property accessor method
    490      *  throws an exception
    491      * @exception NoSuchMethodException if an accessor method for this
    492      *  propety cannot be found
    493      */
    494     public String getNestedProperty(
    495                                     Object bean,
    496                                     String name,
    497                                     String pattern)
    498                                         throws
    499                                             IllegalAccessException,
    500                                             InvocationTargetException,
    501                                             NoSuchMethodException {
    502
    503         Object value = getPropertyUtils().getNestedProperty(bean, name);
    504         return getLocaleConvertUtils().convert(value, pattern);
    505     }
    506
    507     /***
    508      * Return the value of the (possibly nested) locale-sensitive property
    509      * of the specified name, for the specified bean, as a String using the default
    510      * conversion pattern of the corresponding {@link LocaleConverter}.
    511      *
    512      * @param bean Bean whose property is to be extracted
    513      * @param name Possibly nested name of the property to be extracted
    514      * @return The nested property's value, converted to a String
    515      *
    516      * @exception IllegalAccessException if the caller does not have
    517      *  access to the property accessor method
    518      * @exception IllegalArgumentException if a nested reference to a
    519      *  property returns null
    520      * @exception InvocationTargetException if the property accessor method
    521      *  throws an exception
    522      * @exception NoSuchMethodException if an accessor method for this
    523      *  propety cannot be found
    524      */
    525     public String getNestedProperty(Object bean, String name)
    526                                     throws
    527                                         IllegalAccessException,
    528                                         InvocationTargetException,
    529                                         NoSuchMethodException {
    530
    531         return getNestedProperty(bean, name, null);
    532     }
    533
    534     /***
    535      * Return the value of the specified locale-sensitive property
    536      * of the specified bean, no matter which property reference
    537      * format is used, as a String using the specified conversion pattern.
    538      *
    539      * @param bean Bean whose property is to be extracted
    540      * @param name Possibly indexed and/or nested name of the property
    541      *  to be extracted
    542      * @param pattern The conversion pattern
    543      * @return The nested property's value, converted to a String
    544      *
    545      * @exception IllegalAccessException if the caller does not have
    546      *  access to the property accessor method
    547      * @exception InvocationTargetException if the property accessor method
    548      *  throws an exception
    549      * @exception NoSuchMethodException if an accessor method for this
    550      *  propety cannot be found
    551      */
    552     public String getProperty(Object bean, String name, String pattern)
    553                                 throws
    554                                     IllegalAccessException,
    555                                     InvocationTargetException,
    556                                     NoSuchMethodException {
    557
    558         return getNestedProperty(bean, name, pattern);
    559     }
    560
    561     /***
    562      * Return the value of the specified locale-sensitive property
    563      * of the specified bean, no matter which property reference
    564      * format is used, as a String using the default
    565      * conversion pattern of the corresponding {@link LocaleConverter}.
    566      *
    567      * @param bean Bean whose property is to be extracted
    568      * @param name Possibly indexed and/or nested name of the property
    569      *  to be extracted
    570      * @return The property's value, converted to a String
    571      *
    572      * @exception IllegalAccessException if the caller does not have
    573      *  access to the property accessor method
    574      * @exception InvocationTargetException if the property accessor method
    575      *  throws an exception
    576      * @exception NoSuchMethodException if an accessor method for this
    577      *  propety cannot be found
    578      */
    579     public String getProperty(Object bean, String name)
    580                                 throws
    581                                     IllegalAccessException,
    582                                     InvocationTargetException,
    583                                     NoSuchMethodException {
    584
    585         return getNestedProperty(bean, name);
    586     }
    587
    588     /***
    589      * Set the specified locale-sensitive property value, performing type
    590      * conversions as required to conform to the type of the destination property
    591      * using the default conversion pattern of the corresponding {@link LocaleConverter}.
    592      *
    593      * @param bean Bean on which setting is to be performed
    594      * @param name Property name (can be nested/indexed/mapped/combo)
    595      * @param value Value to be set
    596      *
    597      * @exception IllegalAccessException if the caller does not have
    598      *  access to the property accessor method
    599      * @exception InvocationTargetException if the property accessor method
    600      *  throws an exception
    601      */
    602     public void setProperty(Object bean, String name, Object value)
    603                                 throws
    604                                     IllegalAccessException,
    605                                     InvocationTargetException {
    606
    607         setProperty(bean, name, value, null);
    608     }
    609
    610     /***
    611      * Set the specified locale-sensitive property value, performing type
    612      * conversions as required to conform to the type of the destination
    613      * property using the specified conversion pattern.
    614      *
    615      * @param bean Bean on which setting is to be performed
    616      * @param name Property name (can be nested/indexed/mapped/combo)
    617      * @param value Value to be set
    618      * @param pattern The conversion pattern
    619      *
    620      * @exception IllegalAccessException if the caller does not have
    621      *  access to the property accessor method
    622      * @exception InvocationTargetException if the property accessor method
    623      *  throws an exception
    624      */
    625     public void setProperty(
    626                             Object bean,
    627                             String name,
    628                             Object value,
    629                             String pattern)
    630                                 throws
    631                                     IllegalAccessException,
    632                                     InvocationTargetException {
    633
    634         // Trace logging (if enabled)
    635         if (log.isTraceEnabled()) {
    636             StringBuffer sb = new StringBuffer("  setProperty(");
    637             sb.append(bean);
    638             sb.append(", ");
    639             sb.append(name);
    640             sb.append(", ");
    641             if (value == null) {
    642                 sb.append("<NULL>");
    643             }
    644             else if (value instanceof String) {
    645                 sb.append((String) value);
    646             }
    647             else if (value instanceof String[]) {
    648                 String[] values = (String[]) value;
    649                 sb.append('[');
    650                 for (int i = 0; i < values.length; i++) {
    651                     if (i > 0) {
    652                         sb.append(',');
    653                     }
    654                     sb.append(values[i]);
    655                 }
    656                 sb.append(']');
    657             }
    658             else {
    659                 sb.append(value.toString());
    660             }
    661             sb.append(')');
    662             log.trace(sb.toString());
    663         }
    664
    665         // Resolve any nested expression to get the actual target bean
    666         Object target = bean;
    667         Resolver resolver = getPropertyUtils().getResolver();
    668         while (resolver.hasNested(name)) {
    669             try {
    670                 target = getPropertyUtils().getProperty(target, resolver.next(name));
    671                 name = resolver.remove(name);
    672             } catch (NoSuchMethodException e) {
    673                 return; // Skip this property setter
    674             }
    675         }
    676         if (log.isTraceEnabled()) {
    677             log.trace("    Target bean = " + target);
    678             log.trace("    Target name = " + name);
    679         }
    680
    681         // Declare local variables we will require
    682         String propName = resolver.getProperty(name); // Simple name of target property
    683         int index  = resolver.getIndex(name);         // Indexed subscript value (if any)
    684         String key = resolver.getKey(name);           // Mapped key value (if any)
    685
    686         Class type = definePropertyType(target, name, propName);
    687         if (type != null) {
    688             Object newValue = convert(type, index, value, pattern);
    689             invokeSetter(target, propName, key, index, newValue);
    690         }
    691     }
    692
    693     /***
    694      * Calculate the property type.
    695      *
    696      * @param target The bean
    697      * @param name The property name
    698      * @param propName The Simple name of target property
    699      * @return The property's type
    700      *
    701      * @exception IllegalAccessException if the caller does not have
    702      *  access to the property accessor method
    703      * @exception InvocationTargetException if the property accessor method
    704      *  throws an exception
    705      */
    706     protected Class definePropertyType(Object target, String name, String propName)
    707             throws IllegalAccessException, InvocationTargetException {
    708
    709         Class type = null;               // Java type of target property
    710
    711         if (target instanceof DynaBean) {
    712             DynaClass dynaClass = ((DynaBean) target).getDynaClass();
    713             DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
    714             if (dynaProperty == null) {
    715                 return null; // Skip this property setter
    716             }
    717             type = dynaProperty.getType();
    718         }
    719         else {
    720             PropertyDescriptor descriptor = null;
    721             try {
    722                 descriptor =
    723                         getPropertyUtils().getPropertyDescriptor(target, name);
    724                 if (descriptor == null) {
    725                     return null; // Skip this property setter
    726                 }
    727             }
    728             catch (NoSuchMethodException e) {
    729                 return null; // Skip this property setter
    730             }
    731             if (descriptor instanceof MappedPropertyDescriptor) {
    732                 type = ((MappedPropertyDescriptor) descriptor).
    733                         getMappedPropertyType();
    734             }
    735             else if (descriptor instanceof IndexedPropertyDescriptor) {
    736                 type = ((IndexedPropertyDescriptor) descriptor).
    737                         getIndexedPropertyType();
    738             }
    739             else {
    740                 type = descriptor.getPropertyType();
    741             }
    742         }
    743         return type;
    744     }
    745
    746     /***
    747      * Convert the specified value to the required type using the
    748      * specified conversion pattern.
    749      *
    750      * @param type The Java type of target property
    751      * @param index The indexed subscript value (if any)
    752      * @param value The value to be converted
    753      * @param pattern The conversion pattern
    754      * @return The converted value
    755      */
    756     protected Object convert(Class type, int index, Object value, String pattern) {
    757
    758         if (log.isTraceEnabled()) {
    759             log.trace("Converting value '" + value + "' to type:" + type);
    760         }
    761
    762         Object newValue = null;
    763
    764         if (type.isArray() && (index < 0)) { // Scalar value into array
    765             if (value instanceof String) {
    766                 String[] values = new String[1];
    767                 values[0] = (String) value;
    768                 newValue = getLocaleConvertUtils().convert(values, type, pattern);
    769             }
    770             else if (value instanceof String[]) {
    771                 newValue = getLocaleConvertUtils().convert((String[]) value, type, pattern);
    772             }
    773             else {
    774                 newValue = value;
    775             }
    776         }
    777         else if (type.isArray()) {         // Indexed value into array
    778             if (value instanceof String) {
    779                 newValue = getLocaleConvertUtils().convert((String) value,
    780                         type.getComponentType(), pattern);
    781             }
    782             else if (value instanceof String[]) {
    783                 newValue = getLocaleConvertUtils().convert(((String[]) value)[0],
    784                         type.getComponentType(), pattern);
    785             }
    786             else {
    787                 newValue = value;
    788             }
    789         }
    790         else {                             // Value into scalar
    791             if (value instanceof String) {
    792                 newValue = getLocaleConvertUtils().convert((String) value, type, pattern);
    793             }
    794             else if (value instanceof String[]) {
    795                 newValue = getLocaleConvertUtils().convert(((String[]) value)[0],
    796                         type, pattern);
    797             }
    798             else {
    799                 newValue = value;
    800             }
    801         }
    802         return newValue;
    803     }
    804
    805     /***
    806      *  Convert the specified value to the required type.
    807      *
    808      * @param type The Java type of target property
    809      * @param index The indexed subscript value (if any)
    810      * @param value The value to be converted
    811      * @return The converted value
    812      */
    813     protected Object convert(Class type, int index, Object value) {
    814
    815         Object newValue = null;
    816
    817         if (type.isArray() && (index < 0)) { // Scalar value into array
    818             if (value instanceof String) {
    819                 String[] values = new String[1];
    820                 values[0] = (String) value;
    821                 newValue = ConvertUtils.convert(values, type);
    822             }
    823             else if (value instanceof String[]) {
    824                 newValue = ConvertUtils.convert((String[]) value, type);
    825             }
    826             else {
    827                 newValue = value;
    828             }
    829         }
    830         else if (type.isArray()) {         // Indexed value into array
    831             if (value instanceof String) {
    832                 newValue = ConvertUtils.convert((String) value,
    833                         type.getComponentType());
    834             }
    835             else if (value instanceof String[]) {
    836                 newValue = ConvertUtils.convert(((String[]) value)[0],
    837                         type.getComponentType());
    838             }
    839             else {
    840                 newValue = value;
    841             }
    842         }
    843         else {                             // Value into scalar
    844             if (value instanceof String) {
    845                 newValue = ConvertUtils.convert((String) value, type);
    846             }
    847             else if (value instanceof String[]) {
    848                 newValue = ConvertUtils.convert(((String[]) value)[0],
    849                         type);
    850             }
    851             else {
    852                 newValue = value;
    853             }
    854         }
    855         return newValue;
    856     }
    857
    858     /***
    859      * Invoke the setter method.
    860      *
    861      * @param target The bean
    862      * @param propName The Simple name of target property
    863      * @param key The Mapped key value (if any)
    864      * @param index The indexed subscript value (if any)
    865      * @param newValue The value to be set
    866      *
    867      * @exception IllegalAccessException if the caller does not have
    868      *  access to the property accessor method
    869      * @exception InvocationTargetException if the property accessor method
    870      *  throws an exception
    871      */
    872     protected void invokeSetter(Object target, String propName, String key, int index, Object newValue)
    873             throws IllegalAccessException, InvocationTargetException {
    874
    875         try {
    876             if (index >= 0) {
    877                 getPropertyUtils().setIndexedProperty(target, propName,
    878                         index, newValue);
    879             }
    880             else if (key != null) {
    881                 getPropertyUtils().setMappedProperty(target, propName,
    882                         key, newValue);
    883             }
    884             else {
    885                 getPropertyUtils().setProperty(target, propName, newValue);
    886             }
    887         }
    888         catch (NoSuchMethodException e) {
    889             throw new InvocationTargetException
    890                     (e, "Cannot set " + propName);
    891         }
    892     }
    893
    894     /***
    895      * Resolve any nested expression to get the actual target property.
    896      *
    897      * @param bean The bean
    898      * @param name The property name
    899      * @return The property's descriptor
    900      *
    901      * @exception IllegalAccessException if the caller does not have
    902      *  access to the property accessor method
    903      * @exception InvocationTargetException if the property accessor method
    904      *  throws an exception
    905      * @deprecated Property name expressions are now processed by
    906      * the configured {@link Resolver} implementation and this method
    907      * is no longer used by BeanUtils.
    908      */
    909     protected Descriptor calculate(Object bean, String name)
    910             throws IllegalAccessException, InvocationTargetException {
    911
    912         // Resolve any nested expression to get the actual target bean
    913         Object target = bean;
    914         Resolver resolver = getPropertyUtils().getResolver();
    915         while (resolver.hasNested(name)) {
    916             try {
    917                 target = getPropertyUtils().getProperty(target, resolver.next(name));
    918                 name = resolver.remove(name);
    919             } catch (NoSuchMethodException e) {
    920                 return null; // Skip this property setter
    921             }
    922         }
    923         if (log.isTraceEnabled()) {
    924             log.trace("    Target bean = " + target);
    925             log.trace("    Target name = " + name);
    926         }
    927
    928         // Declare local variables we will require
    929         String propName = resolver.getProperty(name); // Simple name of target property
    930         int index  = resolver.getIndex(name);         // Indexed subscript value (if any)
    931         String key = resolver.getKey(name);           // Mapped key value (if any)
    932
    933         return new Descriptor(target, name, propName, key, index);
    934     }
    935
    936     /***
    937      * @deprecated Property name expressions are now processed by
    938      * the configured {@link Resolver} implementation and this class
    939      * is no longer used by BeanUtils.
    940      */
    941     protected class Descriptor {
    942
    943         private int index = -1;    // Indexed subscript value (if any)
    944         private String name;
    945         private String propName;   // Simple name of target property
    946         private String key;        // Mapped key value (if any)
    947         private Object target;
    948
    949         /***
    950          * Construct a descriptor instance for the target bean and property.
    951          *
    952          * @param target The target bean
    953          * @param name The property name (includes indexed/mapped expr)
    954          * @param propName The property name
    955          * @param key The mapped property key (if any)
    956          * @param index The indexed property index (if any)
    957          */
    958         public Descriptor(Object target, String name, String propName, String key, int index) {
    959
    960             setTarget(target);
    961             setName(name);
    962             setPropName(propName);
    963             setKey(key);
    964             setIndex(index);
    965         }
    966
    967         /***
    968          * Return the target bean.
    969          *
    970          * @return The descriptors target bean
    971          */
    972         public Object getTarget() {
    973             return target;
    974         }
    975
    976         /***
    977          * Set the target bean.
    978          *
    979          * @param target The target bean
    980          */
    981         public void setTarget(Object target) {
    982             this.target = target;
    983         }
    984
    985         /***
    986          * Return the mapped property key.
    987          *
    988          * @return the mapped property key (if any)
    989          */
    990         public String getKey() {
    991             return key;
    992         }
    993
    994         /***
    995          * Set the mapped property key.
    996          *
    997          * @param key The mapped property key (if any)
    998          */
    999         public void setKey(String key) {
    1000             this.key = key;
    1001         }
    1002
    1003         /***
    1004          * Return indexed property index.
    1005          *
    1006          * @return indexed property index (if any)
    1007          */
    1008         public int getIndex() {
    1009             return index;
    1010         }
    1011
    1012         /***
    1013          * Set the indexed property index.
    1014          *
    1015          * @param index The indexed property index (if any)
    1016          */
    1017         public void setIndex(int index) {
    1018             this.index = index;
    1019         }
    1020
    1021         /***
    1022          * Return property name (includes indexed/mapped expr).
    1023          *
    1024          * @return The property name (includes indexed/mapped expr)
    1025          */
    1026         public String getName() {
    1027             return name;
    1028         }
    1029
    1030         /***
    1031          * Set the property name (includes indexed/mapped expr).
    1032          *
    1033          * @param name The property name (includes indexed/mapped expr)
    1034          */
    1035         public void setName(String name) {
    1036             this.name = name;
    1037         }
    1038
    1039         /***
    1040          * Return the property name.
    1041          *
    1042          * @return The property name
    1043          */
    1044         public String getPropName() {
    1045             return propName;
    1046         }
    1047
    1048         /***
    1049          * Set the property name.
    1050          *
    1051          * @param propName The property name
    1052          */
    1053         public void setPropName(String propName) {
    1054             this.propName = propName;
    1055         }
    1056     }
    1057 }
    1058
    1059