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