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