LocaleBeanUtilsBean.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.beanutils2.locale;

  18. import java.beans.IndexedPropertyDescriptor;
  19. import java.beans.PropertyDescriptor;
  20. import java.lang.reflect.InvocationTargetException;
  21. import java.util.Locale;

  22. import org.apache.commons.beanutils2.BeanUtilsBean;
  23. import org.apache.commons.beanutils2.ContextClassLoaderLocal;
  24. import org.apache.commons.beanutils2.ConvertUtils;
  25. import org.apache.commons.beanutils2.ConvertUtilsBean;
  26. import org.apache.commons.beanutils2.DynaBean;
  27. import org.apache.commons.beanutils2.DynaClass;
  28. import org.apache.commons.beanutils2.DynaProperty;
  29. import org.apache.commons.beanutils2.MappedPropertyDescriptor;
  30. import org.apache.commons.beanutils2.PropertyUtilsBean;
  31. import org.apache.commons.beanutils2.expression.Resolver;
  32. import org.apache.commons.logging.Log;
  33. import org.apache.commons.logging.LogFactory;

  34. /**
  35.  * <p>
  36.  * Utility methods for populating JavaBeans properties via reflection in a locale-dependent manner.
  37.  * </p>
  38.  *
  39.  * @since 1.7
  40.  */
  41. public class LocaleBeanUtilsBean extends BeanUtilsBean {

  42.     /**
  43.      * Contains {@code LocaleBeanUtilsBean} instances indexed by context classloader.
  44.      */
  45.     private static final ContextClassLoaderLocal<LocaleBeanUtilsBean> LOCALE_BEANS_BY_CLASSLOADER = new ContextClassLoaderLocal<LocaleBeanUtilsBean>() {
  46.         // Creates the default instance used when the context classloader is unavailable
  47.         @Override
  48.         protected LocaleBeanUtilsBean initialValue() {
  49.             return new LocaleBeanUtilsBean();
  50.         }
  51.     };

  52.     /** All logging goes through this logger */
  53.     private static final Log LOG = LogFactory.getLog(LocaleBeanUtilsBean.class);

  54.     /**
  55.      * Gets singleton instance
  56.      *
  57.      * @return the singleton instance
  58.      */
  59.     public static LocaleBeanUtilsBean getLocaleBeanUtilsInstance() {
  60.         return LOCALE_BEANS_BY_CLASSLOADER.get();
  61.     }

  62.     /**
  63.      * Sets the instance which provides the functionality for {@link LocaleBeanUtils}. This is a pseudo-singleton - an single instance is provided per (thread)
  64.      * context classloader. This mechanism provides isolation for web apps deployed in the same container.
  65.      *
  66.      * @param newInstance a new singleton instance
  67.      */
  68.     public static void setInstance(final LocaleBeanUtilsBean newInstance) {
  69.         LOCALE_BEANS_BY_CLASSLOADER.set(newInstance);
  70.     }

  71.     /** Convertor used by this class */
  72.     private final LocaleConvertUtilsBean localeConvertUtils;

  73.     /** Constructs instance with standard conversion bean */
  74.     public LocaleBeanUtilsBean() {
  75.         this.localeConvertUtils = new LocaleConvertUtilsBean();
  76.     }

  77.     /**
  78.      * Constructs instance that uses given locale conversion
  79.      *
  80.      * @param localeConvertUtils use this {@code localeConvertUtils} to perform conversions
  81.      */
  82.     public LocaleBeanUtilsBean(final LocaleConvertUtilsBean localeConvertUtils) {
  83.         this.localeConvertUtils = localeConvertUtils;
  84.     }

  85.     /**
  86.      * Constructs instance that uses given locale conversion
  87.      *
  88.      * @param localeConvertUtils use this {@code localeConvertUtils} to perform conversions
  89.      * @param convertUtilsBean   use this for standard conversions
  90.      * @param propertyUtilsBean  use this for property conversions
  91.      */
  92.     public LocaleBeanUtilsBean(final LocaleConvertUtilsBean localeConvertUtils, final ConvertUtilsBean convertUtilsBean,
  93.             final PropertyUtilsBean propertyUtilsBean) {
  94.         super(convertUtilsBean, propertyUtilsBean);
  95.         this.localeConvertUtils = localeConvertUtils;
  96.     }

  97.     /**
  98.      * Convert the specified value to the required type.
  99.      *
  100.      * @param type  The Java type of target property
  101.      * @param index The indexed subscript value (if any)
  102.      * @param value The value to be converted
  103.      * @return The converted value
  104.      */
  105.     protected Object convert(final Class<?> type, final int index, final Object value) {
  106.         Object newValue = null;

  107.         if (type.isArray() && index < 0) { // Scalar value into array
  108.             if (value instanceof String) {
  109.                 final String[] values = new String[1];
  110.                 values[0] = (String) value;
  111.                 newValue = ConvertUtils.convert(values, type);
  112.             } else if (value instanceof String[]) {
  113.                 newValue = ConvertUtils.convert((String[]) value, type);
  114.             } else {
  115.                 newValue = value;
  116.             }
  117.         } else if (type.isArray()) { // Indexed value into array
  118.             if (value instanceof String) {
  119.                 newValue = ConvertUtils.convert((String) value, type.getComponentType());
  120.             } else if (value instanceof String[]) {
  121.                 newValue = ConvertUtils.convert(((String[]) value)[0], type.getComponentType());
  122.             } else {
  123.                 newValue = value;
  124.             }
  125.         } else if (value instanceof String) {
  126.             newValue = ConvertUtils.convert((String) value, type);
  127.         } else if (value instanceof String[]) {
  128.             newValue = ConvertUtils.convert(((String[]) value)[0], type);
  129.         } else {
  130.             newValue = value;
  131.         }
  132.         return newValue;
  133.     }

  134.     /**
  135.      * Convert the specified value to the required type using the specified conversion pattern.
  136.      *
  137.      * @param type    The Java type of target property
  138.      * @param index   The indexed subscript value (if any)
  139.      * @param value   The value to be converted
  140.      * @param pattern The conversion pattern
  141.      * @return The converted value
  142.      */
  143.     protected Object convert(final Class<?> type, final int index, final Object value, final String pattern) {
  144.         if (LOG.isTraceEnabled()) {
  145.             LOG.trace("Converting value '" + value + "' to type:" + type);
  146.         }

  147.         Object newValue = null;

  148.         if (type.isArray() && index < 0) { // Scalar value into array
  149.             if (value instanceof String) {
  150.                 final String[] values = new String[1];
  151.                 values[0] = (String) value;
  152.                 newValue = getLocaleConvertUtils().convert(values, type, pattern);
  153.             } else if (value instanceof String[]) {
  154.                 newValue = getLocaleConvertUtils().convert((String[]) value, type, pattern);
  155.             } else {
  156.                 newValue = value;
  157.             }
  158.         } else if (type.isArray()) { // Indexed value into array
  159.             if (value instanceof String) {
  160.                 newValue = getLocaleConvertUtils().convert((String) value, type.getComponentType(), pattern);
  161.             } else if (value instanceof String[]) {
  162.                 newValue = getLocaleConvertUtils().convert(((String[]) value)[0], type.getComponentType(), pattern);
  163.             } else {
  164.                 newValue = value;
  165.             }
  166.         } else if (value instanceof String) {
  167.             newValue = getLocaleConvertUtils().convert((String) value, type, pattern);
  168.         } else if (value instanceof String[]) {
  169.             newValue = getLocaleConvertUtils().convert(((String[]) value)[0], type, pattern);
  170.         } else {
  171.             newValue = value;
  172.         }
  173.         return newValue;
  174.     }

  175.     /**
  176.      * Calculate the property type.
  177.      *
  178.      * @param target   The bean
  179.      * @param name     The property name
  180.      * @param propName The Simple name of target property
  181.      * @return The property's type
  182.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  183.      * @throws InvocationTargetException if the property accessor method throws an exception
  184.      */
  185.     protected Class<?> definePropertyType(final Object target, final String name, final String propName)
  186.             throws IllegalAccessException, InvocationTargetException {
  187.         Class<?> type = null; // Java type of target property

  188.         if (target instanceof DynaBean) {
  189.             final DynaClass dynaClass = ((DynaBean) target).getDynaClass();
  190.             final DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
  191.             if (dynaProperty == null) {
  192.                 return null; // Skip this property setter
  193.             }
  194.             type = dynaProperty.getType();
  195.         } else {
  196.             PropertyDescriptor descriptor = null;
  197.             try {
  198.                 descriptor = getPropertyUtils().getPropertyDescriptor(target, name);
  199.                 if (descriptor == null) {
  200.                     return null; // Skip this property setter
  201.                 }
  202.             } catch (final NoSuchMethodException e) {
  203.                 return null; // Skip this property setter
  204.             }
  205.             if (descriptor instanceof MappedPropertyDescriptor) {
  206.                 type = ((MappedPropertyDescriptor) descriptor).getMappedPropertyType();
  207.             } else if (descriptor instanceof IndexedPropertyDescriptor) {
  208.                 type = ((IndexedPropertyDescriptor) descriptor).getIndexedPropertyType();
  209.             } else {
  210.                 type = descriptor.getPropertyType();
  211.             }
  212.         }
  213.         return type;
  214.     }

  215.     /**
  216.      * Is the pattern to be applied localized (Indicate whether the pattern is localized or not)
  217.      *
  218.      * @return {@code true} if pattern is localized, otherwise {@code false}
  219.      */
  220.     public boolean getApplyLocalized() {
  221.         return getLocaleConvertUtils().getApplyLocalized();
  222.     }

  223.     /**
  224.      * Gets the default Locale
  225.      *
  226.      * @return the default locale
  227.      */
  228.     public Locale getDefaultLocale() {
  229.         return getLocaleConvertUtils().getDefaultLocale();
  230.     }

  231.     /**
  232.      * Gets the value of the specified locale-sensitive indexed property of the specified bean, as a String using the default conversion pattern of the
  233.      * corresponding {@link LocaleConverter}. The zero-relative index of the required value must be included (in square brackets) as a suffix to the property
  234.      * name, or {@code IllegalArgumentException} will be thrown.
  235.      *
  236.      * @param bean Bean whose property is to be extracted
  237.      * @param name {@code propertyname[index]} of the property value to be extracted
  238.      * @return The indexed property's value, converted to a String
  239.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  240.      * @throws InvocationTargetException if the property accessor method throws an exception
  241.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  242.      */
  243.     @Override
  244.     public String getIndexedProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  245.         return getIndexedProperty(bean, name, null);
  246.     }

  247.     /**
  248.      * Gets the value of the specified locale-sensetive indexed property of the specified bean, as a String using the default conversion pattern of the
  249.      * corresponding {@link LocaleConverter}. The index is specified as a method parameter and must *not* be included in the property name expression
  250.      *
  251.      * @param bean  Bean whose property is to be extracted
  252.      * @param name  Simple property name of the property value to be extracted
  253.      * @param index Index of the property value to be extracted
  254.      * @return The indexed property's value, converted to a String
  255.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  256.      * @throws InvocationTargetException if the property accessor method throws an exception
  257.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  258.      */
  259.     @Override
  260.     public String getIndexedProperty(final Object bean, final String name, final int index)
  261.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  262.         return getIndexedProperty(bean, name, index, null);
  263.     }

  264.     /**
  265.      * Gets the value of the specified locale-sensetive indexed property of the specified bean, as a String using the specified conversion pattern. The index is
  266.      * specified as a method parameter and must *not* be included in the property name expression
  267.      *
  268.      * @param bean    Bean whose property is to be extracted
  269.      * @param name    Simple property name of the property value to be extracted
  270.      * @param index   Index of the property value to be extracted
  271.      * @param pattern The conversion pattern
  272.      * @return The indexed property's value, converted to a String
  273.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  274.      * @throws InvocationTargetException if the property accessor method throws an exception
  275.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  276.      */
  277.     public String getIndexedProperty(final Object bean, final String name, final int index, final String pattern)
  278.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  279.         final Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
  280.         return getLocaleConvertUtils().convert(value, pattern);
  281.     }

  282.     /**
  283.      * Gets the value of the specified locale-sensitive indexed property of the specified bean, as a String. The zero-relative index of the required value must
  284.      * be included (in square brackets) as a suffix to the property name, or {@code IllegalArgumentException} will be thrown.
  285.      *
  286.      * @param bean    Bean whose property is to be extracted
  287.      * @param name    {@code propertyname[index]} of the property value to be extracted
  288.      * @param pattern The conversion pattern
  289.      * @return The indexed property's value, converted to a String
  290.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  291.      * @throws InvocationTargetException if the property accessor method throws an exception
  292.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  293.      */
  294.     public String getIndexedProperty(final Object bean, final String name, final String pattern)
  295.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  296.         final Object value = getPropertyUtils().getIndexedProperty(bean, name);
  297.         return getLocaleConvertUtils().convert(value, pattern);
  298.     }

  299.     /**
  300.      * Gets the bean instance used for conversions
  301.      *
  302.      * @return the locale converter bean instance
  303.      */
  304.     public LocaleConvertUtilsBean getLocaleConvertUtils() {
  305.         return localeConvertUtils;
  306.     }

  307.     /**
  308.      * Gets the value of the specified locale-sensitive mapped property of the specified bean, as a String using the default conversion pattern of the
  309.      * corresponding {@link LocaleConverter}. The String-valued key of the required value must be included (in parentheses) as a suffix to the property name, or
  310.      * {@code IllegalArgumentException} will be thrown.
  311.      *
  312.      * @param bean Bean whose property is to be extracted
  313.      * @param name {@code propertyname(index)} of the property value to be extracted
  314.      * @return The mapped property's value, converted to a String
  315.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  316.      * @throws InvocationTargetException if the property accessor method throws an exception
  317.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  318.      */
  319.     @Override
  320.     public String getMappedProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  321.         return getMappedPropertyLocale(bean, name, null);
  322.     }

  323.     /**
  324.      * Gets the value of the specified mapped locale-sensitive property of the specified bean, as a String The key is specified as a method parameter and must
  325.      * *not* be included in the property name expression
  326.      *
  327.      * @param bean Bean whose property is to be extracted
  328.      * @param name Simple property name of the property value to be extracted
  329.      * @param key  Lookup key of the property value to be extracted
  330.      * @return The mapped property's value, converted to a String
  331.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  332.      * @throws InvocationTargetException if the property accessor method throws an exception
  333.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  334.      */
  335.     @Override
  336.     public String getMappedProperty(final Object bean, final String name, final String key)
  337.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  338.         return getMappedProperty(bean, name, key, null);
  339.     }

  340.     /**
  341.      * Gets the value of the specified mapped locale-sensitive property of the specified bean, as a String using the specified conversion pattern. The key is
  342.      * specified as a method parameter and must *not* be included in the property name expression.
  343.      *
  344.      * @param bean    Bean whose property is to be extracted
  345.      * @param name    Simple property name of the property value to be extracted
  346.      * @param key     Lookup key of the property value to be extracted
  347.      * @param pattern The conversion pattern
  348.      * @return The mapped property's value, converted to a String
  349.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  350.      * @throws InvocationTargetException if the property accessor method throws an exception
  351.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  352.      */
  353.     public String getMappedProperty(final Object bean, final String name, final String key, final String pattern)
  354.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  355.         final Object value = getPropertyUtils().getMappedProperty(bean, name, key);
  356.         return getLocaleConvertUtils().convert(value, pattern);
  357.     }

  358.     /**
  359.      * Gets the value of the specified locale-sensitive mapped property of the specified bean, as a String using the specified pattern. The String-valued key of
  360.      * the required value must be included (in parentheses) as a suffix to the property name, or {@code IllegalArgumentException} will be thrown.
  361.      *
  362.      * @param bean    Bean whose property is to be extracted
  363.      * @param name    {@code propertyname(index)} of the property value to be extracted
  364.      * @param pattern The conversion pattern
  365.      * @return The mapped property's value, converted to a String
  366.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  367.      * @throws InvocationTargetException if the property accessor method throws an exception
  368.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  369.      */
  370.     public String getMappedPropertyLocale(final Object bean, final String name, final String pattern)
  371.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  372.         final Object value = getPropertyUtils().getMappedProperty(bean, name);
  373.         return getLocaleConvertUtils().convert(value, pattern);
  374.     }

  375.     /**
  376.      * Gets the value of the (possibly nested) locale-sensitive property of the specified name, for the specified bean, as a String using the default conversion
  377.      * pattern of the corresponding {@link LocaleConverter}.
  378.      *
  379.      * @param bean Bean whose property is to be extracted
  380.      * @param name Possibly nested name of the property to be extracted
  381.      * @return The nested property's value, converted to a String
  382.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  383.      * @throws IllegalArgumentException  if a nested reference to a property returns null
  384.      * @throws InvocationTargetException if the property accessor method throws an exception
  385.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  386.      */
  387.     @Override
  388.     public String getNestedProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  389.         return getNestedProperty(bean, name, null);
  390.     }

  391.     /**
  392.      * Gets the value of the (possibly nested) locale-sensitive property of the specified name, for the specified bean, as a String using the specified pattern.
  393.      *
  394.      * @param bean    Bean whose property is to be extracted
  395.      * @param name    Possibly nested name of the property to be extracted
  396.      * @param pattern The conversion pattern
  397.      * @return The nested property's value, converted to a String
  398.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  399.      * @throws IllegalArgumentException  if a nested reference to a property returns null
  400.      * @throws InvocationTargetException if the property accessor method throws an exception
  401.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  402.      */
  403.     public String getNestedProperty(final Object bean, final String name, final String pattern)
  404.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  405.         final Object value = getPropertyUtils().getNestedProperty(bean, name);
  406.         return getLocaleConvertUtils().convert(value, pattern);
  407.     }

  408.     /**
  409.      * Gets the value of the specified locale-sensitive property of the specified bean, no matter which property reference format is used, as a String using the
  410.      * default conversion pattern of the corresponding {@link LocaleConverter}.
  411.      *
  412.      * @param bean Bean whose property is to be extracted
  413.      * @param name Possibly indexed and/or nested name of the property to be extracted
  414.      * @return The property's value, converted to a String
  415.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  416.      * @throws InvocationTargetException if the property accessor method throws an exception
  417.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  418.      */
  419.     @Override
  420.     public String getProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  421.         return getNestedProperty(bean, name);
  422.     }

  423.     /**
  424.      * Gets the value of the specified locale-sensitive property of the specified bean, no matter which property reference format is used, as a String using the
  425.      * specified conversion pattern.
  426.      *
  427.      * @param bean    Bean whose property is to be extracted
  428.      * @param name    Possibly indexed and/or nested name of the property to be extracted
  429.      * @param pattern The conversion pattern
  430.      * @return The nested property's value, converted to a String
  431.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  432.      * @throws InvocationTargetException if the property accessor method throws an exception
  433.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  434.      */
  435.     public String getProperty(final Object bean, final String name, final String pattern)
  436.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  437.         return getNestedProperty(bean, name, pattern);
  438.     }

  439.     /**
  440.      * Gets the value of the specified simple locale-sensitive property of the specified bean, converted to a String using the default conversion pattern of the
  441.      * corresponding {@link LocaleConverter}.
  442.      *
  443.      * @param bean Bean whose property is to be extracted
  444.      * @param name Name of the property to be extracted
  445.      * @return The property's value, converted to a String
  446.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  447.      * @throws InvocationTargetException if the property accessor method throws an exception
  448.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  449.      */
  450.     @Override
  451.     public String getSimpleProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  452.         return getSimpleProperty(bean, name, null);
  453.     }

  454.     /**
  455.      * Gets the value of the specified simple locale-sensitive property of the specified bean, converted to a String using the specified conversion pattern.
  456.      *
  457.      * @param bean    Bean whose property is to be extracted
  458.      * @param name    Name of the property to be extracted
  459.      * @param pattern The conversion pattern
  460.      * @return The property's value, converted to a String
  461.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  462.      * @throws InvocationTargetException if the property accessor method throws an exception
  463.      * @throws NoSuchMethodException     if an accessor method for this property cannot be found
  464.      */
  465.     public String getSimpleProperty(final Object bean, final String name, final String pattern)
  466.             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  467.         final Object value = getPropertyUtils().getSimpleProperty(bean, name);
  468.         return getLocaleConvertUtils().convert(value, pattern);
  469.     }

  470.     /**
  471.      * Invoke the setter method.
  472.      *
  473.      * @param target   The bean
  474.      * @param propName The Simple name of target property
  475.      * @param key      The Mapped key value (if any)
  476.      * @param index    The indexed subscript value (if any)
  477.      * @param newValue The value to be set
  478.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  479.      * @throws InvocationTargetException if the property accessor method throws an exception
  480.      */
  481.     protected void invokeSetter(final Object target, final String propName, final String key, final int index, final Object newValue)
  482.             throws IllegalAccessException, InvocationTargetException {

  483.         try {
  484.             if (index >= 0) {
  485.                 getPropertyUtils().setIndexedProperty(target, propName, index, newValue);
  486.             } else if (key != null) {
  487.                 getPropertyUtils().setMappedProperty(target, propName, key, newValue);
  488.             } else {
  489.                 getPropertyUtils().setProperty(target, propName, newValue);
  490.             }
  491.         } catch (final NoSuchMethodException e) {
  492.             throw new InvocationTargetException(e, "Cannot set " + propName);
  493.         }
  494.     }

  495.     /**
  496.      * Sets whether the pattern is applied localized (Indicate whether the pattern is localized or not)
  497.      *
  498.      * @param newApplyLocalized {@code true} if pattern is localized, otherwise {@code false}
  499.      */
  500.     public void setApplyLocalized(final boolean newApplyLocalized) {
  501.         getLocaleConvertUtils().setApplyLocalized(newApplyLocalized);
  502.     }

  503.     /**
  504.      * Sets the default Locale.
  505.      *
  506.      * @param locale the default locale
  507.      */
  508.     public void setDefaultLocale(final Locale locale) {
  509.         getLocaleConvertUtils().setDefaultLocale(locale);
  510.     }

  511.     /**
  512.      * Sets the specified locale-sensitive property value, performing type conversions as required to conform to the type of the destination property using the
  513.      * default conversion pattern of the corresponding {@link LocaleConverter}.
  514.      *
  515.      * @param bean  Bean on which setting is to be performed
  516.      * @param name  Property name (can be nested/indexed/mapped/combo)
  517.      * @param value Value to be set
  518.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  519.      * @throws InvocationTargetException if the property accessor method throws an exception
  520.      */
  521.     @Override
  522.     public void setProperty(final Object bean, final String name, final Object value) throws IllegalAccessException, InvocationTargetException {
  523.         setProperty(bean, name, value, null);
  524.     }

  525.     /**
  526.      * Sets the specified locale-sensitive property value, performing type conversions as required to conform to the type of the destination property using the
  527.      * specified conversion pattern.
  528.      *
  529.      * @param bean    Bean on which setting is to be performed
  530.      * @param name    Property name (can be nested/indexed/mapped/combo)
  531.      * @param value   Value to be set
  532.      * @param pattern The conversion pattern
  533.      * @throws IllegalAccessException    if the caller does not have access to the property accessor method
  534.      * @throws InvocationTargetException if the property accessor method throws an exception
  535.      */
  536.     public void setProperty(final Object bean, String name, final Object value, final String pattern) throws IllegalAccessException, InvocationTargetException {
  537.         // Trace logging (if enabled)
  538.         if (LOG.isTraceEnabled()) {
  539.             final StringBuilder sb = new StringBuilder("  setProperty(");
  540.             sb.append(bean);
  541.             sb.append(", ");
  542.             sb.append(name);
  543.             sb.append(", ");
  544.             if (value == null) {
  545.                 sb.append("<NULL>");
  546.             } else if (value instanceof String) {
  547.                 sb.append((String) value);
  548.             } else if (value instanceof String[]) {
  549.                 final String[] values = (String[]) value;
  550.                 sb.append('[');
  551.                 for (int i = 0; i < values.length; i++) {
  552.                     if (i > 0) {
  553.                         sb.append(',');
  554.                     }
  555.                     sb.append(values[i]);
  556.                 }
  557.                 sb.append(']');
  558.             } else {
  559.                 sb.append(value.toString());
  560.             }
  561.             sb.append(')');
  562.             LOG.trace(sb.toString());
  563.         }

  564.         // Resolve any nested expression to get the actual target bean
  565.         Object target = bean;
  566.         final Resolver resolver = getPropertyUtils().getResolver();
  567.         while (resolver.hasNested(name)) {
  568.             try {
  569.                 target = getPropertyUtils().getProperty(target, resolver.next(name));
  570.                 name = resolver.remove(name);
  571.             } catch (final NoSuchMethodException e) {
  572.                 return; // Skip this property setter
  573.             }
  574.         }
  575.         if (LOG.isTraceEnabled()) {
  576.             LOG.trace("    Target bean = " + target);
  577.             LOG.trace("    Target name = " + name);
  578.         }

  579.         // Declare local variables we will require
  580.         final String propName = resolver.getProperty(name); // Simple name of target property
  581.         final int index = resolver.getIndex(name); // Indexed subscript value (if any)
  582.         final String key = resolver.getKey(name); // Mapped key value (if any)

  583.         final Class<?> type = definePropertyType(target, name, propName);
  584.         if (type != null) {
  585.             final Object newValue = convert(type, index, value, pattern);
  586.             invokeSetter(target, propName, key, index, newValue);
  587.         }
  588.     }
  589. }