Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
LocaleConvertUtilsBean |
|
| 1.2564102564102564;1.256 | ||||
LocaleConvertUtilsBean$1 |
|
| 1.2564102564102564;1.256 | ||||
LocaleConvertUtilsBean$DelegateFastHashMap |
|
| 1.2564102564102564;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 | } |