Coverage Report - org.apache.commons.beanutils.locale.LocaleConvertUtilsBean
 
Classes in this File Line Coverage Branch Coverage Complexity
LocaleConvertUtilsBean
77%
68/88
60%
12/20
1.256
LocaleConvertUtilsBean$1
N/A
N/A
1.256
LocaleConvertUtilsBean$DelegateFastHashMap
43%
10/23
N/A
1.256
 
 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.BeanUtils;
 21  
 import org.apache.commons.beanutils.locale.converters.BigDecimalLocaleConverter;
 22  
 import org.apache.commons.beanutils.locale.converters.BigIntegerLocaleConverter;
 23  
 import org.apache.commons.beanutils.locale.converters.ByteLocaleConverter;
 24  
 import org.apache.commons.beanutils.locale.converters.DoubleLocaleConverter;
 25  
 import org.apache.commons.beanutils.locale.converters.FloatLocaleConverter;
 26  
 import org.apache.commons.beanutils.locale.converters.IntegerLocaleConverter;
 27  
 import org.apache.commons.beanutils.locale.converters.LongLocaleConverter;
 28  
 import org.apache.commons.beanutils.locale.converters.ShortLocaleConverter;
 29  
 import org.apache.commons.beanutils.locale.converters.StringLocaleConverter;
 30  
 import org.apache.commons.beanutils.locale.converters.SqlDateLocaleConverter;
 31  
 import org.apache.commons.beanutils.locale.converters.SqlTimeLocaleConverter;
 32  
 import org.apache.commons.beanutils.locale.converters.SqlTimestampLocaleConverter;
 33  
 
 34  
 import org.apache.commons.collections.FastHashMap;
 35  
 import org.apache.commons.logging.Log;
 36  
 import org.apache.commons.logging.LogFactory;
 37  
 
 38  
 import java.lang.reflect.Array;
 39  
 import java.math.BigDecimal;
 40  
 import java.math.BigInteger;
 41  
 import java.util.Collection;
 42  
 import java.util.Locale;
 43  
 import java.util.Map;
 44  
 import java.util.Set;
 45  
 
 46  
 /**
 47  
  * <p>Utility methods for converting locale-sensitive String scalar values to objects of the
 48  
  * specified Class, String arrays to arrays of the specified Class and
 49  
  * object to locale-sensitive String scalar value.</p>
 50  
  *
 51  
  * <p>This class provides the implementations used by the static utility methods in 
 52  
  * {@link LocaleConvertUtils}.</p>
 53  
  * 
 54  
  * <p>The actual {@link LocaleConverter} instance to be used
 55  
  * can be registered for each possible destination Class. Unless you override them, standard
 56  
  * {@link LocaleConverter} instances are provided for all of the following
 57  
  * destination Classes:</p>
 58  
  * <ul>
 59  
  * <li>java.lang.BigDecimal</li>
 60  
  * <li>java.lang.BigInteger</li>
 61  
  * <li>byte and java.lang.Byte</li>
 62  
  * <li>double and java.lang.Double</li>
 63  
  * <li>float and java.lang.Float</li>
 64  
  * <li>int and java.lang.Integer</li>
 65  
  * <li>long and java.lang.Long</li>
 66  
  * <li>short and java.lang.Short</li>
 67  
  * <li>java.lang.String</li>
 68  
  * <li>java.sql.Date</li>
 69  
  * <li>java.sql.Time</li>
 70  
  * <li>java.sql.Timestamp</li>
 71  
  * </ul>
 72  
  *
 73  
  * <p>For backwards compatibility, the standard locale converters
 74  
  * for primitive types (and the corresponding wrapper classes).
 75  
  *
 76  
  * If you prefer to have another {@link LocaleConverter}
 77  
  * thrown instead, replace the standard {@link LocaleConverter} instances
 78  
  * with ones created with the one of the appropriate constructors.
 79  
  *
 80  
  * It's important that {@link LocaleConverter} should be registered for
 81  
  * the specified locale and Class (or primitive type).
 82  
  *
 83  
  * @author Yauheny Mikulski
 84  
  * @since 1.7
 85  
  */
 86  
 public class LocaleConvertUtilsBean {
 87  
     
 88  
     /** 
 89  
      * Gets singleton instance.
 90  
      * This is the same as the instance used by the default {@link LocaleBeanUtilsBean} singleton.
 91  
      * @return the singleton instance
 92  
      */
 93  
     public static LocaleConvertUtilsBean getInstance() {
 94  60
         return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getLocaleConvertUtils();
 95  
     }
 96  
 
 97  
     // ----------------------------------------------------- Instance Variables
 98  
 
 99  
     /** The locale - default for convertion. */
 100  23
     private Locale defaultLocale = Locale.getDefault();
 101  
 
 102  
     /** Indicate whether the pattern is localized or not */
 103  23
     private boolean applyLocalized = false;
 104  
 
 105  
     /** The <code>Log</code> instance for this class. */
 106  23
     private Log log = LogFactory.getLog(LocaleConvertUtils.class);
 107  
 
 108  
     /** Every entry of the mapConverters is:
 109  
      *  key = locale
 110  
      *  value = FastHashMap of converters for the certain locale.
 111  
      */
 112  23
     private FastHashMap mapConverters = new DelegateFastHashMap(BeanUtils.createCache());
 113  
 
 114  
     // --------------------------------------------------------- Constructors
 115  
 
 116  
     /**
 117  
      *  Makes the state by default (deregisters all converters for all locales)
 118  
      *  and then registers default locale converters.
 119  
      */
 120  23
     public LocaleConvertUtilsBean() {
 121  23
         mapConverters.setFast(false);
 122  23
         deregister();
 123  23
         mapConverters.setFast(true);
 124  23
     }
 125  
     
 126  
     // --------------------------------------------------------- Properties
 127  
      
 128  
     /**
 129  
      * getter for defaultLocale.
 130  
      * @return the default locale
 131  
      */
 132  
     public Locale getDefaultLocale() {
 133  
 
 134  0
         return defaultLocale;
 135  
     }
 136  
 
 137  
     /**
 138  
      * setter for defaultLocale.
 139  
      * @param locale the default locale
 140  
      */
 141  
     public void setDefaultLocale(Locale locale) {
 142  
 
 143  0
         if (locale == null) {
 144  0
             defaultLocale = Locale.getDefault();
 145  
         }
 146  
         else {
 147  0
             defaultLocale = locale;
 148  
         }
 149  0
     }
 150  
     
 151  
     /**
 152  
      * getter for applyLocalized
 153  
      *
 154  
      * @return <code>true</code> if pattern is localized,
 155  
      * otherwise <code>false</code>
 156  
      */
 157  
     public boolean getApplyLocalized() {
 158  0
         return applyLocalized;
 159  
     }
 160  
 
 161  
     /**
 162  
      * setter for applyLocalized
 163  
      *
 164  
      * @param newApplyLocalized <code>true</code> if pattern is localized,
 165  
      * otherwise <code>false</code>
 166  
      */
 167  
     public void setApplyLocalized(boolean newApplyLocalized) {
 168  0
         applyLocalized = newApplyLocalized;
 169  0
     }
 170  
 
 171  
     // --------------------------------------------------------- Methods
 172  
 
 173  
     /**
 174  
      * Convert the specified locale-sensitive value into a String.
 175  
      *
 176  
      * @param value The Value to be converted
 177  
      * @return the converted value
 178  
      *
 179  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 180  
      * underlying Converter
 181  
      */
 182  
     public String convert(Object value) {
 183  11
         return convert(value, defaultLocale, null);
 184  
     }
 185  
 
 186  
     /**
 187  
      * Convert the specified locale-sensitive value into a String
 188  
      * using the conversion pattern.
 189  
      *
 190  
      * @param value The Value to be converted
 191  
      * @param pattern       The convertion pattern
 192  
      * @return the converted value
 193  
      *
 194  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 195  
      * underlying Converter
 196  
      */
 197  
     public String convert(Object value, String pattern) {
 198  0
         return convert(value, defaultLocale, pattern);
 199  
     }
 200  
 
 201  
     /**
 202  
      * Convert the specified locale-sensitive value into a String
 203  
      * using the paticular convertion pattern.
 204  
      *
 205  
      * @param value The Value to be converted
 206  
      * @param locale The locale
 207  
      * @param pattern The convertion pattern
 208  
      * @return the converted value
 209  
      *
 210  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 211  
      * underlying Converter
 212  
      */
 213  
     public String convert(Object value, Locale locale, String pattern) {
 214  
 
 215  11
         LocaleConverter converter = lookup(String.class, locale);
 216  
 
 217  11
         return (String) converter.convert(String.class, value, pattern);
 218  
     }
 219  
 
 220  
     /**
 221  
      * Convert the specified value to an object of the specified class (if
 222  
      * possible).  Otherwise, return a String representation of the value.
 223  
      *
 224  
      * @param value The String scalar value to be converted
 225  
      * @param clazz The Data type to which this value should be converted.
 226  
      * @return the converted value
 227  
      *
 228  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 229  
      * underlying Converter
 230  
      */
 231  
     public Object convert(String value, Class clazz) {
 232  
 
 233  25
         return convert(value, clazz, defaultLocale, null);
 234  
     }
 235  
 
 236  
     /**
 237  
      * Convert the specified value to an object of the specified class (if
 238  
      * possible) using the convertion pattern. Otherwise, return a String
 239  
      * representation of the value.
 240  
      *
 241  
      * @param value The String scalar value to be converted
 242  
      * @param clazz The Data type to which this value should be converted.
 243  
      * @param pattern The convertion pattern
 244  
      * @return the converted value
 245  
      *
 246  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 247  
      * underlying Converter
 248  
      */
 249  
     public Object convert(String value, Class clazz, String pattern) {
 250  
 
 251  4
         return convert(value, clazz, defaultLocale, pattern);
 252  
     }
 253  
 
 254  
     /**
 255  
      * Convert the specified value to an object of the specified class (if
 256  
      * possible) using the convertion pattern. Otherwise, return a String
 257  
      * representation of the value.
 258  
      *
 259  
      * @param value The String scalar value to be converted
 260  
      * @param clazz The Data type to which this value should be converted.
 261  
      * @param locale The locale
 262  
      * @param pattern The convertion pattern
 263  
      * @return the converted value
 264  
      *
 265  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 266  
      * underlying Converter
 267  
      */
 268  
     public Object convert(String value, Class clazz, Locale locale, String pattern) {
 269  
 
 270  33
         if (log.isDebugEnabled()) {
 271  0
             log.debug("Convert string " + value + " to class " +
 272  
                     clazz.getName() + " using " + locale +
 273  
                     " locale and " + pattern + " pattern");
 274  
         }
 275  
 
 276  33
         LocaleConverter converter = lookup(clazz, locale);
 277  
 
 278  33
         if (converter == null) {
 279  0
             converter = lookup(String.class, locale);
 280  
         }
 281  33
         if (log.isTraceEnabled()) {
 282  0
             log.trace("  Using converter " + converter);
 283  
         }
 284  
 
 285  33
         return (converter.convert(clazz, value, pattern));
 286  
     }
 287  
 
 288  
     /**
 289  
      * Convert an array of specified values to an array of objects of the
 290  
      * specified class (if possible) using the convertion pattern.
 291  
      *
 292  
      * @param values Value to be converted (may be null)
 293  
      * @param clazz Java array or element class to be converted to
 294  
      * @param pattern The convertion pattern
 295  
      * @return the converted value
 296  
      *
 297  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 298  
      * underlying Converter
 299  
      */
 300  
     public Object convert(String[] values, Class clazz, String pattern) {
 301  
 
 302  0
         return convert(values, clazz, getDefaultLocale(), pattern);
 303  
     }
 304  
 
 305  
    /**
 306  
     * Convert an array of specified values to an array of objects of the
 307  
     * specified class (if possible) .
 308  
     *
 309  
     * @param values Value to be converted (may be null)
 310  
     * @param clazz Java array or element class to be converted to
 311  
     * @return the converted value
 312  
     *
 313  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 314  
      * underlying Converter
 315  
     */
 316  
    public Object convert(String[] values, Class clazz) {
 317  
 
 318  0
        return convert(values, clazz, getDefaultLocale(), null);
 319  
    }
 320  
 
 321  
     /**
 322  
      * Convert an array of specified values to an array of objects of the
 323  
      * specified class (if possible) using the convertion pattern.
 324  
      *
 325  
      * @param values Value to be converted (may be null)
 326  
      * @param clazz Java array or element class to be converted to
 327  
      * @param locale The locale
 328  
      * @param pattern The convertion pattern
 329  
      * @return the converted value
 330  
      *
 331  
      * @throws org.apache.commons.beanutils.ConversionException if thrown by an
 332  
      * underlying Converter
 333  
      */
 334  
     public Object convert(String[] values, Class clazz, Locale locale, String pattern) {
 335  
 
 336  1
         Class type = clazz;
 337  1
         if (clazz.isArray()) {
 338  1
             type = clazz.getComponentType();
 339  
         }
 340  1
         if (log.isDebugEnabled()) {
 341  0
             log.debug("Convert String[" + values.length + "] to class " +
 342  
                     type.getName() + "[] using " + locale +
 343  
                     " locale and " + pattern + " pattern");
 344  
         }
 345  
 
 346  1
         Object array = Array.newInstance(type, values.length);
 347  2
         for (int i = 0; i < values.length; i++) {
 348  1
             Array.set(array, i, convert(values[i], type, locale, pattern));
 349  
         }
 350  
 
 351  1
         return (array);
 352  
     }
 353  
 
 354  
     /**
 355  
      * Register a custom {@link LocaleConverter} for the specified destination
 356  
      * <code>Class</code>, replacing any previously registered converter.
 357  
      *
 358  
      * @param converter The LocaleConverter to be registered
 359  
      * @param clazz The Destination class for conversions performed by this
 360  
      *  Converter
 361  
      * @param locale The locale
 362  
      */
 363  
     public void register(LocaleConverter converter, Class clazz, Locale locale) {
 364  
 
 365  3
         lookup(locale).put(clazz, converter);
 366  3
     }
 367  
 
 368  
     /**
 369  
      * Remove any registered {@link LocaleConverter}.
 370  
      */
 371  
     public void deregister() {
 372  
 
 373  37
         FastHashMap defaultConverter = lookup(defaultLocale);
 374  
 
 375  37
         mapConverters.setFast(false);
 376  
 
 377  37
         mapConverters.clear();
 378  37
         mapConverters.put(defaultLocale, defaultConverter);
 379  
 
 380  37
         mapConverters.setFast(true);
 381  37
     }
 382  
 
 383  
 
 384  
     /**
 385  
      * Remove any registered {@link LocaleConverter} for the specified locale
 386  
      *
 387  
      * @param locale The locale
 388  
      */
 389  
     public void deregister(Locale locale) {
 390  
 
 391  0
         mapConverters.remove(locale);
 392  0
     }
 393  
 
 394  
 
 395  
     /**
 396  
      * Remove any registered {@link LocaleConverter} for the specified locale and Class.
 397  
      *
 398  
      * @param clazz Class for which to remove a registered Converter
 399  
      * @param locale The locale
 400  
      */
 401  
     public void deregister(Class clazz, Locale locale) {
 402  
 
 403  0
         lookup(locale).remove(clazz);
 404  0
     }
 405  
 
 406  
     /**
 407  
      * Look up and return any registered {@link LocaleConverter} for the specified
 408  
      * destination class and locale; if there is no registered Converter, return
 409  
      * <code>null</code>.
 410  
      *
 411  
      * @param clazz Class for which to return a registered Converter
 412  
      * @param locale The Locale
 413  
      * @return The registered locale Converter, if any
 414  
      */
 415  
     public LocaleConverter lookup(Class clazz, Locale locale) {
 416  
 
 417  44
         LocaleConverter converter = (LocaleConverter) lookup(locale).get(clazz);
 418  
         
 419  44
         if (log.isTraceEnabled()) {
 420  0
             log.trace("LocaleConverter:" + converter);
 421  
         }
 422  
         
 423  44
         return converter;
 424  
     }
 425  
 
 426  
     /**
 427  
      * Look up and return any registered FastHashMap instance for the specified locale;
 428  
      * if there is no registered one, return <code>null</code>.
 429  
      *
 430  
      * @param locale The Locale
 431  
      * @return The FastHashMap instance contains the all {@link LocaleConverter} types for
 432  
      *  the specified locale.
 433  
      * @deprecated This method will be modified to return a Map in the next release.
 434  
      */
 435  
     protected FastHashMap lookup(Locale locale) {
 436  
         FastHashMap localeConverters;
 437  
 
 438  84
         if (locale == null) {
 439  2
             localeConverters = (FastHashMap) mapConverters.get(defaultLocale);
 440  
         }
 441  
         else {
 442  82
             localeConverters = (FastHashMap) mapConverters.get(locale);
 443  
 
 444  82
             if (localeConverters == null) {
 445  23
                 localeConverters = create(locale);
 446  23
                 mapConverters.put(locale, localeConverters);
 447  
             }
 448  
         }
 449  
 
 450  84
         return localeConverters;
 451  
     }
 452  
 
 453  
     /**
 454  
      *  Create all {@link LocaleConverter} types for specified locale.
 455  
      *
 456  
      * @param locale The Locale
 457  
      * @return The FastHashMap instance contains the all {@link LocaleConverter} types
 458  
      *  for the specified locale.
 459  
      * @deprecated This method will be modified to return a Map in the next release.
 460  
      */
 461  
     protected FastHashMap create(Locale locale) {
 462  
 
 463  23
         FastHashMap converter = new DelegateFastHashMap(BeanUtils.createCache());
 464  23
         converter.setFast(false);
 465  
 
 466  23
         converter.put(BigDecimal.class, new BigDecimalLocaleConverter(locale, applyLocalized));
 467  23
         converter.put(BigInteger.class, new BigIntegerLocaleConverter(locale, applyLocalized));
 468  
 
 469  23
         converter.put(Byte.class, new ByteLocaleConverter(locale, applyLocalized));
 470  23
         converter.put(Byte.TYPE, new ByteLocaleConverter(locale, applyLocalized));
 471  
 
 472  23
         converter.put(Double.class, new DoubleLocaleConverter(locale, applyLocalized));
 473  23
         converter.put(Double.TYPE, new DoubleLocaleConverter(locale, applyLocalized));
 474  
 
 475  23
         converter.put(Float.class, new FloatLocaleConverter(locale, applyLocalized));
 476  23
         converter.put(Float.TYPE, new FloatLocaleConverter(locale, applyLocalized));
 477  
 
 478  23
         converter.put(Integer.class, new IntegerLocaleConverter(locale, applyLocalized));
 479  23
         converter.put(Integer.TYPE, new IntegerLocaleConverter(locale, applyLocalized));
 480  
 
 481  23
         converter.put(Long.class, new LongLocaleConverter(locale, applyLocalized));
 482  23
         converter.put(Long.TYPE, new LongLocaleConverter(locale, applyLocalized));
 483  
 
 484  23
         converter.put(Short.class, new ShortLocaleConverter(locale, applyLocalized));
 485  23
         converter.put(Short.TYPE, new ShortLocaleConverter(locale, applyLocalized));
 486  
 
 487  23
         converter.put(String.class, new StringLocaleConverter(locale, applyLocalized));
 488  
 
 489  
         // conversion format patterns of java.sql.* types should correspond to default
 490  
         // behaviour of toString and valueOf methods of these classes
 491  23
         converter.put(java.sql.Date.class, new SqlDateLocaleConverter(locale, "yyyy-MM-dd"));
 492  23
         converter.put(java.sql.Time.class, new SqlTimeLocaleConverter(locale, "HH:mm:ss"));
 493  23
         converter.put( java.sql.Timestamp.class,
 494  
                        new SqlTimestampLocaleConverter(locale, "yyyy-MM-dd HH:mm:ss.S")
 495  
                      );
 496  
 
 497  23
         converter.setFast(true);
 498  
 
 499  23
         return converter;
 500  
     }
 501  
 
 502  
     /**
 503  
      * FastHashMap implementation that uses WeakReferences to overcome
 504  
      * memory leak problems.
 505  
      *
 506  
      * This is a hack to retain binary compatibility with previous
 507  
      * releases (where FastHashMap is exposed in the API), but
 508  
      * use WeakHashMap to resolve memory leaks.
 509  
      */
 510  46
     private static class DelegateFastHashMap extends FastHashMap {
 511  
 
 512  
         private final Map map;
 513  
 
 514  46
         private DelegateFastHashMap(Map map) {
 515  46
             this.map = map;
 516  46
         }
 517  
         public void clear() {
 518  37
             map.clear();
 519  37
         }
 520  
         public boolean containsKey(Object key) {
 521  0
             return map.containsKey(key);
 522  
         }
 523  
         public boolean containsValue(Object value) {
 524  0
             return map.containsValue(value);
 525  
         }
 526  
         public Set entrySet() {
 527  0
             return map.entrySet();
 528  
         }
 529  
         public boolean equals(Object o) {
 530  0
             return map.equals(o);
 531  
         }
 532  
         public Object get(Object key) {
 533  128
             return map.get(key);
 534  
         }
 535  
         public int hashCode() {
 536  0
             return map.hashCode();
 537  
         }
 538  
         public boolean isEmpty() {
 539  0
             return map.isEmpty();
 540  
         }
 541  
         public Set keySet() {
 542  0
             return map.keySet();
 543  
         }
 544  
         public Object put(Object key, Object value) {
 545  477
             return map.put(key, value);
 546  
         }
 547  
         public void putAll(Map m) {
 548  0
             map.putAll(m);
 549  0
         }
 550  
         public Object remove(Object key) {
 551  0
             return map.remove(key);
 552  
         }
 553  
         public int size() {
 554  0
             return map.size();
 555  
         }
 556  
         public Collection values() {
 557  0
             return map.values();
 558  
         }
 559  
         public boolean getFast() {
 560  0
             return BeanUtils.getCacheFast(map);
 561  
         }
 562  
         public void setFast(boolean fast) {
 563  166
             BeanUtils.setCacheFast(map, fast);
 564  166
         }
 565  
     }
 566  
 }