View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.commons.beanutils.locale;
    19
    20  import org.apache.commons.beanutils.locale.converters.BigDecimalLocaleConverter;
    21  import org.apache.commons.beanutils.locale.converters.BigIntegerLocaleConverter;
    22  import org.apache.commons.beanutils.locale.converters.ByteLocaleConverter;
    23  import org.apache.commons.beanutils.locale.converters.DoubleLocaleConverter;
    24  import org.apache.commons.beanutils.locale.converters.FloatLocaleConverter;
    25  import org.apache.commons.beanutils.locale.converters.IntegerLocaleConverter;
    26  import org.apache.commons.beanutils.locale.converters.LongLocaleConverter;
    27  import org.apache.commons.beanutils.locale.converters.ShortLocaleConverter;
    28  import org.apache.commons.beanutils.locale.converters.StringLocaleConverter;
    29  import org.apache.commons.beanutils.locale.converters.SqlDateLocaleConverter;
    30  import org.apache.commons.beanutils.locale.converters.SqlTimeLocaleConverter;
    31  import org.apache.commons.beanutils.locale.converters.SqlTimestampLocaleConverter;
    32
    33  import org.apache.commons.collections.FastHashMap;
    34  import org.apache.commons.logging.Log;
    35  import org.apache.commons.logging.LogFactory;
    36
    37  import java.lang.reflect.Array;
    38  import java.math.BigDecimal;
    39  import java.math.BigInteger;
    40  import java.util.Locale;
    41
    42  /***
    43   * <p>Utility methods for converting locale-sensitive String scalar values to objects of the
    44   * specified Class, String arrays to arrays of the specified Class and
    45   * object to locale-sensitive String scalar value.</p>
    46   *
    47   * <p>This class provides the implementations used by the static utility methods in
    48   * {@link LocaleConvertUtils}.</p>
    49   *
    50   * <p>The actual {@link LocaleConverter} instance to be used
    51   * can be registered for each possible destination Class. Unless you override them, standard
    52   * {@link LocaleConverter} instances are provided for all of the following
    53   * destination Classes:</p>
    54   * <ul>
    55   * <li>java.lang.BigDecimal</li>
    56   * <li>java.lang.BigInteger</li>
    57   * <li>byte and java.lang.Byte</li>
    58   * <li>double and java.lang.Double</li>
    59   * <li>float and java.lang.Float</li>
    60   * <li>int and java.lang.Integer</li>
    61   * <li>long and java.lang.Long</li>
    62   * <li>short and java.lang.Short</li>
    63   * <li>java.lang.String</li>
    64   * <li>java.sql.Date</li>
    65   * <li>java.sql.Time</li>
    66   * <li>java.sql.Timestamp</li>
    67   * </ul>
    68   *
    69   * <p>For backwards compatibility, the standard locale converters
    70   * for primitive types (and the corresponding wrapper classes).
    71   *
    72   * If you prefer to have another {@link LocaleConverter}
    73   * thrown instead, replace the standard {@link LocaleConverter} instances
    74   * with ones created with the one of the appropriate constructors.
    75   *
    76   * It's important that {@link LocaleConverter} should be registered for
    77   * the specified locale and Class (or primitive type).
    78   *
    79   * @author Yauheny Mikulski
    80   * @since 1.7
    81   */
    82  public class LocaleConvertUtilsBean {
    83
    84      /***
    85       * Gets singleton instance.
    86       * This is the same as the instance used by the default {@link LocaleBeanUtilsBean} singleton.
    87       * @return the singleton instance
    88       */
    89      public static LocaleConvertUtilsBean getInstance() {
    90          return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getLocaleConvertUtils();
    91      }
    92
    93      // ----------------------------------------------------- Instance Variables
    94
    95      /*** The locale - default for convertion. */
    96      private Locale defaultLocale = Locale.getDefault();
    97
    98      /*** Indicate whether the pattern is localized or not */
    99      private boolean applyLocalized = false;
    100
    101     /*** The <code>Log</code> instance for this class. */
    102     private Log log = LogFactory.getLog(LocaleConvertUtils.class);
    103
    104     /*** Every entry of the mapConverters is:
    105      *  key = locale
    106      *  value = FastHashMap of converters for the certain locale.
    107      */
    108     private FastHashMap mapConverters = new FastHashMap();
    109
    110     // --------------------------------------------------------- Constructors
    111
    112     /***
    113      *  Makes the state by default (deregisters all converters for all locales)
    114      *  and then registers default locale converters.
    115      */
    116     public LocaleConvertUtilsBean() {
    117         deregister();
    118     }
    119
    120     // --------------------------------------------------------- Properties
    121
    122     /***
    123      * getter for defaultLocale.
    124      * @return the default locale
    125      */
    126     public Locale getDefaultLocale() {
    127
    128         return defaultLocale;
    129     }
    130
    131     /***
    132      * setter for defaultLocale.
    133      * @param locale the default locale
    134      */
    135     public void setDefaultLocale(Locale locale) {
    136
    137         if (locale == null) {
    138             defaultLocale = Locale.getDefault();
    139         }
    140         else {
    141             defaultLocale = locale;
    142         }
    143     }
    144
    145     /***
    146      * getter for applyLocalized
    147      *
    148      * @return <code>true</code> if pattern is localized,
    149      * otherwise <code>false</code>
    150      */
    151     public boolean getApplyLocalized() {
    152         return applyLocalized;
    153     }
    154
    155     /***
    156      * setter for applyLocalized
    157      *
    158      * @param newApplyLocalized <code>true</code> if pattern is localized,
    159      * otherwise <code>false</code>
    160      */
    161     public void setApplyLocalized(boolean newApplyLocalized) {
    162         applyLocalized = newApplyLocalized;
    163     }
    164
    165     // --------------------------------------------------------- Methods
    166
    167     /***
    168      * Convert the specified locale-sensitive value into a String.
    169      *
    170      * @param value The Value to be converted
    171      * @return the converted value
    172      *
    173      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    174      * underlying Converter
    175      */
    176     public String convert(Object value) {
    177         return convert(value, defaultLocale, null);
    178     }
    179
    180     /***
    181      * Convert the specified locale-sensitive value into a String
    182      * using the conversion pattern.
    183      *
    184      * @param value The Value to be converted
    185      * @param pattern       The convertion pattern
    186      * @return the converted value
    187      *
    188      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    189      * underlying Converter
    190      */
    191     public String convert(Object value, String pattern) {
    192         return convert(value, defaultLocale, pattern);
    193     }
    194
    195     /***
    196      * Convert the specified locale-sensitive value into a String
    197      * using the paticular convertion pattern.
    198      *
    199      * @param value The Value to be converted
    200      * @param locale The locale
    201      * @param pattern The convertion pattern
    202      * @return the converted value
    203      *
    204      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    205      * underlying Converter
    206      */
    207     public String convert(Object value, Locale locale, String pattern) {
    208
    209         LocaleConverter converter = lookup(String.class, locale);
    210
    211         return (String) converter.convert(String.class, value, pattern);
    212     }
    213
    214     /***
    215      * Convert the specified value to an object of the specified class (if
    216      * possible).  Otherwise, return a String representation of the value.
    217      *
    218      * @param value The String scalar value to be converted
    219      * @param clazz The Data type to which this value should be converted.
    220      * @return the converted value
    221      *
    222      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    223      * underlying Converter
    224      */
    225     public Object convert(String value, Class clazz) {
    226
    227         return convert(value, clazz, defaultLocale, null);
    228     }
    229
    230     /***
    231      * Convert the specified value to an object of the specified class (if
    232      * possible) using the convertion pattern. Otherwise, return a String
    233      * representation of the value.
    234      *
    235      * @param value The String scalar value to be converted
    236      * @param clazz The Data type to which this value should be converted.
    237      * @param pattern The convertion pattern
    238      * @return the converted value
    239      *
    240      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    241      * underlying Converter
    242      */
    243     public Object convert(String value, Class clazz, String pattern) {
    244
    245         return convert(value, clazz, defaultLocale, pattern);
    246     }
    247
    248     /***
    249      * Convert the specified value to an object of the specified class (if
    250      * possible) using the convertion pattern. Otherwise, return a String
    251      * representation of the value.
    252      *
    253      * @param value The String scalar value to be converted
    254      * @param clazz The Data type to which this value should be converted.
    255      * @param locale The locale
    256      * @param pattern The convertion pattern
    257      * @return the converted value
    258      *
    259      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    260      * underlying Converter
    261      */
    262     public Object convert(String value, Class clazz, Locale locale, String pattern) {
    263
    264         if (log.isDebugEnabled()) {
    265             log.debug("Convert string " + value + " to class " +
    266                     clazz.getName() + " using " + locale.toString() +
    267                     " locale and " + pattern + " pattern");
    268         }
    269
    270         LocaleConverter converter = lookup(clazz, locale);
    271
    272         if (converter == null) {
    273             converter = lookup(String.class, locale);
    274         }
    275         if (log.isTraceEnabled()) {
    276             log.trace("  Using converter " + converter);
    277         }
    278
    279         return (converter.convert(clazz, value, pattern));
    280     }
    281
    282     /***
    283      * Convert an array of specified values to an array of objects of the
    284      * specified class (if possible) using the convertion pattern.
    285      *
    286      * @param values Value to be converted (may be null)
    287      * @param clazz Java array or element class to be converted to
    288      * @param pattern The convertion pattern
    289      * @return the converted value
    290      *
    291      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    292      * underlying Converter
    293      */
    294     public Object convert(String[] values, Class clazz, String pattern) {
    295
    296         return convert(values, clazz, getDefaultLocale(), pattern);
    297     }
    298
    299    /***
    300     * Convert an array of specified values to an array of objects of the
    301     * specified class (if possible) .
    302     *
    303     * @param values Value to be converted (may be null)
    304     * @param clazz Java array or element class to be converted to
    305     * @return the converted value
    306     *
    307      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    308      * underlying Converter
    309     */
    310    public Object convert(String[] values, Class clazz) {
    311
    312        return convert(values, clazz, getDefaultLocale(), null);
    313    }
    314
    315     /***
    316      * Convert an array of specified values to an array of objects of the
    317      * specified class (if possible) using the convertion pattern.
    318      *
    319      * @param values Value to be converted (may be null)
    320      * @param clazz Java array or element class to be converted to
    321      * @param locale The locale
    322      * @param pattern The convertion pattern
    323      * @return the converted value
    324      *
    325      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
    326      * underlying Converter
    327      */
    328     public Object convert(String[] values, Class clazz, Locale locale, String pattern) {
    329
    330         Class type = clazz;
    331         if (clazz.isArray()) {
    332             type = clazz.getComponentType();
    333         }
    334         if (log.isDebugEnabled()) {
    335             log.debug("Convert String[" + values.length + "] to class " +
    336                     type.getName() + "[] using " + locale.toString() +
    337                     " locale and " + pattern + " pattern");
    338         }
    339
    340         Object array = Array.newInstance(type, values.length);
    341         for (int i = 0; i < values.length; i++) {
    342             Array.set(array, i, convert(values[i], type, locale, pattern));
    343         }
    344
    345         return (array);
    346     }
    347
    348     /***
    349      * Register a custom {@link LocaleConverter} for the specified destination
    350      * <code>Class</code>, replacing any previously registered converter.
    351      *
    352      * @param converter The LocaleConverter to be registered
    353      * @param clazz The Destination class for conversions performed by this
    354      *  Converter
    355      * @param locale The locale
    356      */
    357     public void register(LocaleConverter converter, Class clazz, Locale locale) {
    358
    359         lookup(locale).put(clazz, converter);
    360     }
    361
    362     /***
    363      * Remove any registered {@link LocaleConverter}.
    364      */
    365     public void deregister() {
    366
    367         FastHashMap defaultConverter = lookup(defaultLocale);
    368
    369         mapConverters.setFast(false);
    370
    371         mapConverters.clear();
    372         mapConverters.put(defaultLocale, defaultConverter);
    373
    374         mapConverters.setFast(true);
    375     }
    376
    377
    378     /***
    379      * Remove any registered {@link LocaleConverter} for the specified locale
    380      *
    381      * @param locale The locale
    382      */
    383     public void deregister(Locale locale) {
    384
    385         mapConverters.remove(locale);
    386     }
    387
    388
    389     /***
    390      * Remove any registered {@link LocaleConverter} for the specified locale and Class.
    391      *
    392      * @param clazz Class for which to remove a registered Converter
    393      * @param locale The locale
    394      */
    395     public void deregister(Class clazz, Locale locale) {
    396
    397         lookup(locale).remove(clazz);
    398     }
    399
    400     /***
    401      * Look up and return any registered {@link LocaleConverter} for the specified
    402      * destination class and locale; if there is no registered Converter, return
    403      * <code>null</code>.
    404      *
    405      * @param clazz Class for which to return a registered Converter
    406      * @param locale The Locale
    407      * @return The registered locale Converter, if any
    408      */
    409     public LocaleConverter lookup(Class clazz, Locale locale) {
    410
    411         LocaleConverter converter = (LocaleConverter) lookup(locale).get(clazz);
    412
    413         if (log.isTraceEnabled()) {
    414             log.trace("LocaleConverter:" + converter);
    415         }
    416
    417         return converter;
    418     }
    419
    420     /***
    421      * Look up and return any registered FastHashMap instance for the specified locale;
    422      * if there is no registered one, return <code>null</code>.
    423      *
    424      * @param locale The Locale
    425      * @return The FastHashMap instance contains the all {@link LocaleConverter} types for
    426      *  the specified locale.
    427      * @deprecated This method will be modified to return a Map in the next release.
    428      */
    429     protected FastHashMap lookup(Locale locale) {
    430         FastHashMap localeConverters;
    431
    432         if (locale == null) {
    433             localeConverters = (FastHashMap) mapConverters.get(defaultLocale);
    434         }
    435         else {
    436             localeConverters = (FastHashMap) mapConverters.get(locale);
    437
    438             if (localeConverters == null) {
    439                 localeConverters = create(locale);
    440                 mapConverters.put(locale, localeConverters);
    441             }
    442         }
    443
    444         return localeConverters;
    445     }
    446
    447     /***
    448      *  Create all {@link LocaleConverter} types for specified locale.
    449      *
    450      * @param locale The Locale
    451      * @return The FastHashMap instance contains the all {@link LocaleConverter} types
    452      *  for the specified locale.
    453      * @deprecated This method will be modified to return a Map in the next release.
    454      */
    455     protected FastHashMap create(Locale locale) {
    456
    457         FastHashMap converter = new FastHashMap();
    458         converter.setFast(false);
    459
    460         converter.put(BigDecimal.class, new BigDecimalLocaleConverter(locale, applyLocalized));
    461         converter.put(BigInteger.class, new BigIntegerLocaleConverter(locale, applyLocalized));
    462
    463         converter.put(Byte.class, new ByteLocaleConverter(locale, applyLocalized));
    464         converter.put(Byte.TYPE, new ByteLocaleConverter(locale, applyLocalized));
    465
    466         converter.put(Double.class, new DoubleLocaleConverter(locale, applyLocalized));
    467         converter.put(Double.TYPE, new DoubleLocaleConverter(locale, applyLocalized));
    468
    469         converter.put(Float.class, new FloatLocaleConverter(locale, applyLocalized));
    470         converter.put(Float.TYPE, new FloatLocaleConverter(locale, applyLocalized));
    471
    472         converter.put(Integer.class, new IntegerLocaleConverter(locale, applyLocalized));
    473         converter.put(Integer.TYPE, new IntegerLocaleConverter(locale, applyLocalized));
    474
    475         converter.put(Long.class, new LongLocaleConverter(locale, applyLocalized));
    476         converter.put(Long.TYPE, new LongLocaleConverter(locale, applyLocalized));
    477
    478         converter.put(Short.class, new ShortLocaleConverter(locale, applyLocalized));
    479         converter.put(Short.TYPE, new ShortLocaleConverter(locale, applyLocalized));
    480
    481         converter.put(String.class, new StringLocaleConverter(locale, applyLocalized));
    482
    483         // conversion format patterns of java.sql.* types should correspond to default
    484         // behaviour of toString and valueOf methods of these classes
    485         converter.put(java.sql.Date.class, new SqlDateLocaleConverter(locale, "yyyy-MM-dd"));
    486         converter.put(java.sql.Time.class, new SqlTimeLocaleConverter(locale, "HH:mm:ss"));
    487         converter.put( java.sql.Timestamp.class,
    488                        new SqlTimestampLocaleConverter(locale, "yyyy-MM-dd HH:mm:ss.S")
    489                      );
    490
    491         converter.setFast(true);
    492
    493         return converter;
    494     }
    495 }