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