1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils;
19
20
21 import java.io.File;
22 import java.lang.reflect.Array;
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25 import java.net.URL;
26 import java.sql.Date;
27 import java.sql.Time;
28 import java.sql.Timestamp;
29 import org.apache.commons.beanutils.converters.BigDecimalConverter;
30 import org.apache.commons.beanutils.converters.BigIntegerConverter;
31 import org.apache.commons.beanutils.converters.BooleanConverter;
32 import org.apache.commons.beanutils.converters.BooleanArrayConverter;
33 import org.apache.commons.beanutils.converters.ByteConverter;
34 import org.apache.commons.beanutils.converters.ByteArrayConverter;
35 import org.apache.commons.beanutils.converters.CharacterConverter;
36 import org.apache.commons.beanutils.converters.CharacterArrayConverter;
37 import org.apache.commons.beanutils.converters.ClassConverter;
38 import org.apache.commons.beanutils.converters.DoubleConverter;
39 import org.apache.commons.beanutils.converters.DoubleArrayConverter;
40 import org.apache.commons.beanutils.converters.FileConverter;
41 import org.apache.commons.beanutils.converters.FloatConverter;
42 import org.apache.commons.beanutils.converters.FloatArrayConverter;
43 import org.apache.commons.beanutils.converters.IntegerConverter;
44 import org.apache.commons.beanutils.converters.IntegerArrayConverter;
45 import org.apache.commons.beanutils.converters.LongConverter;
46 import org.apache.commons.beanutils.converters.LongArrayConverter;
47 import org.apache.commons.beanutils.converters.ShortConverter;
48 import org.apache.commons.beanutils.converters.ShortArrayConverter;
49 import org.apache.commons.beanutils.converters.SqlDateConverter;
50 import org.apache.commons.beanutils.converters.SqlTimeConverter;
51 import org.apache.commons.beanutils.converters.SqlTimestampConverter;
52 import org.apache.commons.beanutils.converters.StringConverter;
53 import org.apache.commons.beanutils.converters.StringArrayConverter;
54 import org.apache.commons.beanutils.converters.URLConverter;
55 import org.apache.commons.collections.FastHashMap;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59
60 /**
61 * <p>Utility methods for converting String scalar values to objects of the
62 * specified Class, String arrays to arrays of the specified Class. The
63 * actual {@link Converter} instance to be used can be registered for each
64 * possible destination Class. Unless you override them, standard
65 * {@link Converter} instances are provided for all of the following
66 * destination Classes:</p>
67 * <ul>
68 * <li>java.lang.BigDecimal</li>
69 * <li>java.lang.BigInteger</li>
70 * <li>boolean and java.lang.Boolean</li>
71 * <li>byte and java.lang.Byte</li>
72 * <li>char and java.lang.Character</li>
73 * <li>java.lang.Class</li>
74 * <li>double and java.lang.Double</li>
75 * <li>float and java.lang.Float</li>
76 * <li>int and java.lang.Integer</li>
77 * <li>long and java.lang.Long</li>
78 * <li>short and java.lang.Short</li>
79 * <li>java.lang.String</li>
80 * <li>java.io.File</li>
81 * <li>java.net.URL</li>
82 * <li>java.sql.Date</li>
83 * <li>java.sql.Time</li>
84 * <li>java.sql.Timestamp</li>
85 * </ul>
86 *
87 * <p>For backwards compatibility, the standard Converters for primitive
88 * types (and the corresponding wrapper classes) return a defined
89 * default value when a conversion error occurs. If you prefer to have a
90 * {@link ConversionException} thrown instead, replace the standard Converter
91 * instances with instances created with the zero-arguments constructor. For
92 * example, to cause the Converters for integers to throw an exception on
93 * conversion errors, you could do this:</p>
94 * <pre>
95 * // No-args constructor gets the version that throws exceptions
96 * Converter myConverter =
97 * new org.apache.commons.beanutils.converter.IntegerConverter();
98 * ConvertUtils.register(myConverter, Integer.TYPE); // Native type
99 * ConvertUtils.register(myConverter, Integer.class); // Wrapper class
100 * </pre>
101 *
102 * @author Craig R. McClanahan
103 * @author Ralph Schaer
104 * @author Chris Audley
105 * @author James Strachan
106 * @version $Revision: 1.12.2.1 $ $Date: 2004/07/27 21:44:26 $
107 * @since 1.7
108 */
109
110 public class ConvertUtilsBean {
111
112
113 /** Get singleton instance */
114 protected static ConvertUtilsBean getInstance() {
115 return BeanUtilsBean.getInstance().getConvertUtils();
116 }
117
118
119
120
121 /**
122 * The set of {@link Converter}s that can be used to convert Strings
123 * into objects of a specified Class, keyed by the destination Class.
124 */
125 private FastHashMap converters = new FastHashMap();
126
127 /**
128 * The <code>Log</code> instance for this class.
129 */
130 private Log log = LogFactory.getLog(ConvertUtils.class);
131
132
133
134 /** Construct a bean with standard converters registered */
135 public ConvertUtilsBean() {
136 converters.setFast(false);
137 deregister();
138 converters.setFast(true);
139 }
140
141
142
143
144
145
146 /**
147 * The default value for Boolean conversions.
148 * @deprecated Register replacement converters for Boolean.TYPE and
149 * Boolean.class instead
150 */
151 private Boolean defaultBoolean = Boolean.FALSE;
152
153 /**
154 * Gets the default value for Boolean conversions.
155 * @deprecated Register replacement converters for Boolean.TYPE and
156 * Boolean.class instead
157 */
158 public boolean getDefaultBoolean() {
159 return (defaultBoolean.booleanValue());
160 }
161
162 /**
163 * Sets the default value for Boolean conversions.
164 * @deprecated Register replacement converters for Boolean.TYPE and
165 * Boolean.class instead
166 */
167 public void setDefaultBoolean(boolean newDefaultBoolean) {
168 defaultBoolean = new Boolean(newDefaultBoolean);
169 register(new BooleanConverter(defaultBoolean), Boolean.TYPE);
170 register(new BooleanConverter(defaultBoolean), Boolean.class);
171 }
172
173
174 /**
175 * The default value for Byte conversions.
176 * @deprecated Register replacement converters for Byte.TYPE and
177 * Byte.class instead
178 */
179 private Byte defaultByte = new Byte((byte) 0);
180
181 /**
182 * Gets the default value for Byte conversions.
183 * @deprecated Register replacement converters for Byte.TYPE and
184 * Byte.class instead
185 */
186 public byte getDefaultByte() {
187 return (defaultByte.byteValue());
188 }
189
190 /**
191 * Sets the default value for Byte conversions.
192 * @deprecated Register replacement converters for Byte.TYPE and
193 * Byte.class instead
194 */
195 public void setDefaultByte(byte newDefaultByte) {
196 defaultByte = new Byte(newDefaultByte);
197 register(new ByteConverter(defaultByte), Byte.TYPE);
198 register(new ByteConverter(defaultByte), Byte.class);
199 }
200
201
202 /**
203 * The default value for Character conversions.
204 * @deprecated Register replacement converters for Character.TYPE and
205 * Character.class instead
206 */
207 private Character defaultCharacter = new Character(' ');
208
209 /**
210 * Gets the default value for Character conversions.
211 * @deprecated Register replacement converters for Character.TYPE and
212 * Character.class instead
213 */
214 public char getDefaultCharacter() {
215 return (defaultCharacter.charValue());
216 }
217
218 /**
219 * Sets the default value for Character conversions.
220 * @deprecated Register replacement converters for Character.TYPE and
221 * Character.class instead
222 */
223 public void setDefaultCharacter(char newDefaultCharacter) {
224 defaultCharacter = new Character(newDefaultCharacter);
225 register(new CharacterConverter(defaultCharacter),
226 Character.TYPE);
227 register(new CharacterConverter(defaultCharacter),
228 Character.class);
229 }
230
231
232 /**
233 * The default value for Double conversions.
234 * @deprecated Register replacement converters for Double.TYPE and
235 * Double.class instead
236 */
237 private Double defaultDouble = new Double((double) 0.0);
238
239 /**
240 * Gets the default value for Double conversions.
241 * @deprecated Register replacement converters for Double.TYPE and
242 * Double.class instead
243 */
244 public double getDefaultDouble() {
245 return (defaultDouble.doubleValue());
246 }
247
248 /**
249 * Sets the default value for Double conversions.
250 * @deprecated Register replacement converters for Double.TYPE and
251 * Double.class instead
252 */
253 public void setDefaultDouble(double newDefaultDouble) {
254 defaultDouble = new Double(newDefaultDouble);
255 register(new DoubleConverter(defaultDouble), Double.TYPE);
256 register(new DoubleConverter(defaultDouble), Double.class);
257 }
258
259
260 /**
261 * The default value for Float conversions.
262 * @deprecated Register replacement converters for Float.TYPE and
263 * Float.class instead
264 */
265 private Float defaultFloat = new Float((float) 0.0);
266
267 /**
268 * Gets the default value for Float conversions.
269 * @deprecated Register replacement converters for Float.TYPE and
270 * Float.class instead
271 */
272 public float getDefaultFloat() {
273 return (defaultFloat.floatValue());
274 }
275
276 /**
277 * Sets the default value for Float conversions.
278 * @deprecated Register replacement converters for Float.TYPE and
279 * Float.class instead
280 */
281 public void setDefaultFloat(float newDefaultFloat) {
282 defaultFloat = new Float(newDefaultFloat);
283 register(new FloatConverter(defaultFloat), Float.TYPE);
284 register(new FloatConverter(defaultFloat), Float.class);
285 }
286
287
288 /**
289 * The default value for Integer conversions.
290 * @deprecated Register replacement converters for Integer.TYPE and
291 * Integer.class instead
292 */
293 private Integer defaultInteger = new Integer(0);
294
295 /**
296 * Gets the default value for Integer conversions.
297 * @deprecated Register replacement converters for Integer.TYPE and
298 * Integer.class instead
299 */
300 public int getDefaultInteger() {
301 return (defaultInteger.intValue());
302 }
303
304 /**
305 * Sets the default value for Integer conversions.
306 * @deprecated Register replacement converters for Integer.TYPE and
307 * Integer.class instead
308 */
309 public void setDefaultInteger(int newDefaultInteger) {
310 defaultInteger = new Integer(newDefaultInteger);
311 register(new IntegerConverter(defaultInteger), Integer.TYPE);
312 register(new IntegerConverter(defaultInteger), Integer.class);
313 }
314
315
316 /**
317 * The default value for Long conversions.
318 * @deprecated Register replacement converters for Long.TYPE and
319 * Long.class instead
320 */
321 private Long defaultLong = new Long((long) 0);
322
323 /**
324 * Gets the default value for Long conversions.
325 * @deprecated Register replacement converters for Long.TYPE and
326 * Long.class instead
327 */
328 public long getDefaultLong() {
329 return (defaultLong.longValue());
330 }
331
332 /**
333 * Sets the default value for Long conversions.
334 * @deprecated Register replacement converters for Long.TYPE and
335 * Long.class instead
336 */
337 public void setDefaultLong(long newDefaultLong) {
338 defaultLong = new Long(newDefaultLong);
339 register(new LongConverter(defaultLong), Long.TYPE);
340 register(new LongConverter(defaultLong), Long.class);
341 }
342
343
344 /**
345 * The default value for Short conversions.
346 * @deprecated Register replacement converters for Short.TYPE and
347 * Short.class instead
348 */
349 private static Short defaultShort = new Short((short) 0);
350
351 /**
352 * Gets the default value for Short conversions.
353 * @deprecated Register replacement converters for Short.TYPE and
354 * Short.class instead
355 */
356 public short getDefaultShort() {
357 return (defaultShort.shortValue());
358 }
359
360 /**
361 * Sets the default value for Short conversions.
362 * @deprecated Register replacement converters for Short.TYPE and
363 * Short.class instead
364 */
365 public void setDefaultShort(short newDefaultShort) {
366 defaultShort = new Short(newDefaultShort);
367 register(new ShortConverter(defaultShort), Short.TYPE);
368 register(new ShortConverter(defaultShort), Short.class);
369 }
370
371
372
373 /**
374 * Convert the specified value into a String. If the specified value
375 * is an array, the first element (converted to a String) will be
376 * returned. The registered {@link Converter} for the
377 * <code>java.lang.String</code> class will be used, which allows
378 * applications to customize Object->String conversions (the default
379 * implementation simply uses toString()).
380 *
381 * @param value Value to be converted (may be null)
382 */
383 public String convert(Object value) {
384
385 if (value == null) {
386 return ((String) null);
387 } else if (value.getClass().isArray()) {
388 if (Array.getLength(value) < 1) {
389 return (null);
390 }
391 value = Array.get(value, 0);
392 if (value == null) {
393 return ((String) null);
394 } else {
395 Converter converter = lookup(String.class);
396 return ((String) converter.convert(String.class, value));
397 }
398 } else {
399 Converter converter = lookup(String.class);
400 return ((String) converter.convert(String.class, value));
401 }
402
403 }
404
405
406 /**
407 * Convert the specified value to an object of the specified class (if
408 * possible). Otherwise, return a String representation of the value.
409 *
410 * @param value Value to be converted (may be null)
411 * @param clazz Java class to be converted to
412 *
413 * @exception ConversionException if thrown by an underlying Converter
414 */
415 public Object convert(String value, Class clazz) {
416
417 if (log.isDebugEnabled()) {
418 log.debug("Convert string '" + value + "' to class '" +
419 clazz.getName() + "'");
420 }
421 Converter converter = lookup(clazz);
422 if (converter == null) {
423 converter = lookup(String.class);
424 }
425 if (log.isTraceEnabled()) {
426 log.trace(" Using converter " + converter);
427 }
428 return (converter.convert(clazz, value));
429
430 }
431
432
433 /**
434 * Convert an array of specified values to an array of objects of the
435 * specified class (if possible). If the specified Java class is itself
436 * an array class, this class will be the type of the returned value.
437 * Otherwise, an array will be constructed whose component type is the
438 * specified class.
439 *
440 * @param values Values to be converted (may be null)
441 * @param clazz Java array or element class to be converted to
442 *
443 * @exception ConversionException if thrown by an underlying Converter
444 */
445 public Object convert(String values[], Class clazz) {
446
447 Class type = clazz;
448 if (clazz.isArray()) {
449 type = clazz.getComponentType();
450 }
451 if (log.isDebugEnabled()) {
452 log.debug("Convert String[" + values.length + "] to class '" +
453 type.getName() + "[]'");
454 }
455 Converter converter = lookup(type);
456 if (converter == null) {
457 converter = lookup(String.class);
458 }
459 if (log.isTraceEnabled()) {
460 log.trace(" Using converter " + converter);
461 }
462 Object array = Array.newInstance(type, values.length);
463 for (int i = 0; i < values.length; i++) {
464 Array.set(array, i, converter.convert(type, values[i]));
465 }
466 return (array);
467
468 }
469
470
471 /**
472 * Remove all registered {@link Converter}s, and re-establish the
473 * standard Converters.
474 */
475 public void deregister() {
476
477 boolean booleanArray[] = new boolean[0];
478 byte byteArray[] = new byte[0];
479 char charArray[] = new char[0];
480 double doubleArray[] = new double[0];
481 float floatArray[] = new float[0];
482 int intArray[] = new int[0];
483 long longArray[] = new long[0];
484 short shortArray[] = new short[0];
485 String stringArray[] = new String[0];
486
487 converters.clear();
488 register(BigDecimal.class, new BigDecimalConverter());
489 register(BigInteger.class, new BigIntegerConverter());
490 register(Boolean.TYPE, new BooleanConverter(defaultBoolean));
491 register(Boolean.class, new BooleanConverter(defaultBoolean));
492 register(booleanArray.getClass(),
493 new BooleanArrayConverter(booleanArray));
494 register(Byte.TYPE, new ByteConverter(defaultByte));
495 register(Byte.class, new ByteConverter(defaultByte));
496 register(byteArray.getClass(),
497 new ByteArrayConverter(byteArray));
498 register(Character.TYPE,
499 new CharacterConverter(defaultCharacter));
500 register(Character.class,
501 new CharacterConverter(defaultCharacter));
502 register(charArray.getClass(),
503 new CharacterArrayConverter(charArray));
504 register(Class.class, new ClassConverter());
505 register(Double.TYPE, new DoubleConverter(defaultDouble));
506 register(Double.class, new DoubleConverter(defaultDouble));
507 register(doubleArray.getClass(),
508 new DoubleArrayConverter(doubleArray));
509 register(Float.TYPE, new FloatConverter(defaultFloat));
510 register(Float.class, new FloatConverter(defaultFloat));
511 register(floatArray.getClass(),
512 new FloatArrayConverter(floatArray));
513 register(Integer.TYPE, new IntegerConverter(defaultInteger));
514 register(Integer.class, new IntegerConverter(defaultInteger));
515 register(intArray.getClass(),
516 new IntegerArrayConverter(intArray));
517 register(Long.TYPE, new LongConverter(defaultLong));
518 register(Long.class, new LongConverter(defaultLong));
519 register(longArray.getClass(),
520 new LongArrayConverter(longArray));
521 register(Short.TYPE, new ShortConverter(defaultShort));
522 register(Short.class, new ShortConverter(defaultShort));
523 register(shortArray.getClass(),
524 new ShortArrayConverter(shortArray));
525 register(String.class, new StringConverter());
526 register(stringArray.getClass(),
527 new StringArrayConverter(stringArray));
528 register(Date.class, new SqlDateConverter());
529 register(Time.class, new SqlTimeConverter());
530 register(Timestamp.class, new SqlTimestampConverter());
531 register(File.class, new FileConverter());
532 register(URL.class, new URLConverter());
533
534 }
535
536 /** strictly for convenience since it has same parameter order as Map.put */
537 private void register(Class clazz, Converter converter) {
538 register(converter, clazz);
539 }
540
541 /**
542 * Remove any registered {@link Converter} for the specified destination
543 * <code>Class</code>.
544 *
545 * @param clazz Class for which to remove a registered Converter
546 */
547 public void deregister(Class clazz) {
548
549 converters.remove(clazz);
550
551 }
552
553
554 /**
555 * Look up and return any registered {@link Converter} for the specified
556 * destination class; if there is no registered Converter, return
557 * <code>null</code>.
558 *
559 * @param clazz Class for which to return a registered Converter
560 */
561 public Converter lookup(Class clazz) {
562
563 return ((Converter) converters.get(clazz));
564
565 }
566
567
568 /**
569 * Register a custom {@link Converter} for the specified destination
570 * <code>Class</code>, replacing any previously registered Converter.
571 *
572 * @param converter Converter to be registered
573 * @param clazz Destination class for conversions performed by this
574 * Converter
575 */
576 public void register(Converter converter, Class clazz) {
577
578 converters.put(clazz, converter);
579
580 }
581 }