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