Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ConvertUtilsBean |
|
| 3.2941176470588234;3.294 |
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 | ||
19 | package org.apache.commons.beanutils; | |
20 | ||
21 | ||
22 | import java.io.File; | |
23 | import java.lang.reflect.Array; | |
24 | import java.math.BigDecimal; | |
25 | import java.math.BigInteger; | |
26 | import java.net.URL; | |
27 | import java.sql.Timestamp; | |
28 | import java.util.Calendar; | |
29 | import java.util.Collection; | |
30 | ||
31 | import org.apache.commons.beanutils.converters.ArrayConverter; | |
32 | import org.apache.commons.beanutils.converters.BigDecimalConverter; | |
33 | import org.apache.commons.beanutils.converters.BigIntegerConverter; | |
34 | import org.apache.commons.beanutils.converters.BooleanConverter; | |
35 | import org.apache.commons.beanutils.converters.ByteConverter; | |
36 | import org.apache.commons.beanutils.converters.CalendarConverter; | |
37 | import org.apache.commons.beanutils.converters.CharacterConverter; | |
38 | import org.apache.commons.beanutils.converters.ClassConverter; | |
39 | import org.apache.commons.beanutils.converters.ConverterFacade; | |
40 | import org.apache.commons.beanutils.converters.DateConverter; | |
41 | import org.apache.commons.beanutils.converters.DoubleConverter; | |
42 | import org.apache.commons.beanutils.converters.FileConverter; | |
43 | import org.apache.commons.beanutils.converters.FloatConverter; | |
44 | import org.apache.commons.beanutils.converters.IntegerConverter; | |
45 | import org.apache.commons.beanutils.converters.LongConverter; | |
46 | import org.apache.commons.beanutils.converters.ShortConverter; | |
47 | import org.apache.commons.beanutils.converters.SqlDateConverter; | |
48 | import org.apache.commons.beanutils.converters.SqlTimeConverter; | |
49 | import org.apache.commons.beanutils.converters.SqlTimestampConverter; | |
50 | import org.apache.commons.beanutils.converters.StringConverter; | |
51 | import org.apache.commons.beanutils.converters.URLConverter; | |
52 | import org.apache.commons.logging.Log; | |
53 | import org.apache.commons.logging.LogFactory; | |
54 | ||
55 | ||
56 | /** | |
57 | * <p>Utility methods for converting String scalar values to objects of the | |
58 | * specified Class, String arrays to arrays of the specified Class. The | |
59 | * actual {@link Converter} instance to be used can be registered for each | |
60 | * possible destination Class. Unless you override them, standard | |
61 | * {@link Converter} instances are provided for all of the following | |
62 | * destination Classes:</p> | |
63 | * <ul> | |
64 | * <li>java.lang.BigDecimal (no default value)</li> | |
65 | * <li>java.lang.BigInteger (no default value)</li> | |
66 | * <li>boolean and java.lang.Boolean (default to false)</li> | |
67 | * <li>byte and java.lang.Byte (default to zero)</li> | |
68 | * <li>char and java.lang.Character (default to a space)</li> | |
69 | * <li>java.lang.Class (no default value)</li> | |
70 | * <li>double and java.lang.Double (default to zero)</li> | |
71 | * <li>float and java.lang.Float (default to zero)</li> | |
72 | * <li>int and java.lang.Integer (default to zero)</li> | |
73 | * <li>long and java.lang.Long (default to zero)</li> | |
74 | * <li>short and java.lang.Short (default to zero)</li> | |
75 | * <li>java.lang.String (default to null)</li> | |
76 | * <li>java.io.File (no default value)</li> | |
77 | * <li>java.net.URL (no default value)</li> | |
78 | * <li>java.sql.Date (no default value)</li> | |
79 | * <li>java.sql.Time (no default value)</li> | |
80 | * <li>java.sql.Timestamp (no default value)</li> | |
81 | * </ul> | |
82 | * | |
83 | * <p>For backwards compatibility, the standard Converters for primitive | |
84 | * types (and the corresponding wrapper classes) return a defined | |
85 | * default value when a conversion error occurs. If you prefer to have a | |
86 | * {@link ConversionException} thrown instead, replace the standard Converter | |
87 | * instances with instances created with the zero-arguments constructor. For | |
88 | * example, to cause the Converters for integers to throw an exception on | |
89 | * conversion errors, you could do this:</p> | |
90 | * <pre> | |
91 | * // No-args constructor gets the version that throws exceptions | |
92 | * Converter myConverter = | |
93 | * new org.apache.commons.beanutils.converter.IntegerConverter(); | |
94 | * ConvertUtils.register(myConverter, Integer.TYPE); // Native type | |
95 | * ConvertUtils.register(myConverter, Integer.class); // Wrapper class | |
96 | * </pre> | |
97 | * | |
98 | * <p> | |
99 | * Converters generally treat null input as if it were invalid | |
100 | * input, ie they return their default value if one was specified when the | |
101 | * converter was constructed, and throw an exception otherwise. If you prefer | |
102 | * nulls to be preserved for converters that are converting to objects (not | |
103 | * primitives) then register a converter as above, passing a default value of | |
104 | * null to the converter constructor (and of course registering that converter | |
105 | * only for the .class target). | |
106 | * </p> | |
107 | * | |
108 | * <p> | |
109 | * When a converter is listed above as having no default value, then that | |
110 | * converter will throw an exception when passed null or an invalid value | |
111 | * as its input. In particular, by default the BigInteger and BigDecimal | |
112 | * converters have no default (and are therefore somewhat inconsistent | |
113 | * with the other numerical converters which all have zero as their default). | |
114 | * </p> | |
115 | * | |
116 | * <p> | |
117 | * Converters that generate <i>arrays</i> of each of the primitive types are | |
118 | * also automatically configured (including String[]). When passed null | |
119 | * or invalid input, these return an empty array (not null). See class | |
120 | * AbstractArrayConverter for the supported input formats for these converters. | |
121 | * </p> | |
122 | * | |
123 | * @author Craig R. McClanahan | |
124 | * @author Ralph Schaer | |
125 | * @author Chris Audley | |
126 | * @author James Strachan | |
127 | * @version $Revision: 745079 $ $Date: 2009-02-17 09:04:10 -0500 (Tue, 17 Feb 2009) $ | |
128 | * @since 1.7 | |
129 | */ | |
130 | ||
131 | public class ConvertUtilsBean { | |
132 | ||
133 | 1 | private static final Integer ZERO = new Integer(0); |
134 | 1 | private static final Character SPACE = new Character(' '); |
135 | ||
136 | // ------------------------------------------------------- Class Methods | |
137 | /** | |
138 | * Get singleton instance | |
139 | * @return The singleton instance | |
140 | */ | |
141 | protected static ConvertUtilsBean getInstance() { | |
142 | 498 | return BeanUtilsBean.getInstance().getConvertUtils(); |
143 | } | |
144 | ||
145 | // ------------------------------------------------------- Variables | |
146 | ||
147 | ||
148 | /** | |
149 | * The set of {@link Converter}s that can be used to convert Strings | |
150 | * into objects of a specified Class, keyed by the destination Class. | |
151 | */ | |
152 | 195 | private WeakFastHashMap converters = new WeakFastHashMap(); |
153 | ||
154 | /** | |
155 | * The <code>Log</code> instance for this class. | |
156 | */ | |
157 | 195 | private Log log = LogFactory.getLog(ConvertUtils.class); |
158 | ||
159 | // ------------------------------------------------------- Constructors | |
160 | ||
161 | /** Construct a bean with standard converters registered */ | |
162 | 195 | public ConvertUtilsBean() { |
163 | 195 | converters.setFast(false); |
164 | 195 | deregister(); |
165 | 195 | converters.setFast(true); |
166 | 195 | } |
167 | ||
168 | // --------------------------------------------------------- Public Methods | |
169 | ||
170 | /** | |
171 | * The default value for Boolean conversions. | |
172 | * @deprecated Register replacement converters for Boolean.TYPE and | |
173 | * Boolean.class instead | |
174 | */ | |
175 | 195 | private Boolean defaultBoolean = Boolean.FALSE; |
176 | ||
177 | /** | |
178 | * Gets the default value for Boolean conversions. | |
179 | * @return The default Boolean value | |
180 | * @deprecated Register replacement converters for Boolean.TYPE and | |
181 | * Boolean.class instead | |
182 | */ | |
183 | public boolean getDefaultBoolean() { | |
184 | 0 | return (defaultBoolean.booleanValue()); |
185 | } | |
186 | ||
187 | /** | |
188 | * Sets the default value for Boolean conversions. | |
189 | * @param newDefaultBoolean The default Boolean value | |
190 | * @deprecated Register replacement converters for Boolean.TYPE and | |
191 | * Boolean.class instead | |
192 | */ | |
193 | public void setDefaultBoolean(boolean newDefaultBoolean) { | |
194 | 0 | defaultBoolean = (newDefaultBoolean ? Boolean.TRUE : Boolean.FALSE); |
195 | 0 | register(new BooleanConverter(defaultBoolean), Boolean.TYPE); |
196 | 0 | register(new BooleanConverter(defaultBoolean), Boolean.class); |
197 | 0 | } |
198 | ||
199 | ||
200 | /** | |
201 | * The default value for Byte conversions. | |
202 | * @deprecated Register replacement converters for Byte.TYPE and | |
203 | * Byte.class instead | |
204 | */ | |
205 | 195 | private Byte defaultByte = new Byte((byte) 0); |
206 | ||
207 | /** | |
208 | * Gets the default value for Byte conversions. | |
209 | * @return The default Byte value | |
210 | * @deprecated Register replacement converters for Byte.TYPE and | |
211 | * Byte.class instead | |
212 | */ | |
213 | public byte getDefaultByte() { | |
214 | 0 | return (defaultByte.byteValue()); |
215 | } | |
216 | ||
217 | /** | |
218 | * Sets the default value for Byte conversions. | |
219 | * @param newDefaultByte The default Byte value | |
220 | * @deprecated Register replacement converters for Byte.TYPE and | |
221 | * Byte.class instead | |
222 | */ | |
223 | public void setDefaultByte(byte newDefaultByte) { | |
224 | 0 | defaultByte = new Byte(newDefaultByte); |
225 | 0 | register(new ByteConverter(defaultByte), Byte.TYPE); |
226 | 0 | register(new ByteConverter(defaultByte), Byte.class); |
227 | 0 | } |
228 | ||
229 | ||
230 | /** | |
231 | * The default value for Character conversions. | |
232 | * @deprecated Register replacement converters for Character.TYPE and | |
233 | * Character.class instead | |
234 | */ | |
235 | 195 | private Character defaultCharacter = new Character(' '); |
236 | ||
237 | /** | |
238 | * Gets the default value for Character conversions. | |
239 | * @return The default Character value | |
240 | * @deprecated Register replacement converters for Character.TYPE and | |
241 | * Character.class instead | |
242 | */ | |
243 | public char getDefaultCharacter() { | |
244 | 0 | return (defaultCharacter.charValue()); |
245 | } | |
246 | ||
247 | /** | |
248 | * Sets the default value for Character conversions. | |
249 | * @param newDefaultCharacter The default Character value | |
250 | * @deprecated Register replacement converters for Character.TYPE and | |
251 | * Character.class instead | |
252 | */ | |
253 | public void setDefaultCharacter(char newDefaultCharacter) { | |
254 | 0 | defaultCharacter = new Character(newDefaultCharacter); |
255 | 0 | register(new CharacterConverter(defaultCharacter), |
256 | Character.TYPE); | |
257 | 0 | register(new CharacterConverter(defaultCharacter), |
258 | Character.class); | |
259 | 0 | } |
260 | ||
261 | ||
262 | /** | |
263 | * The default value for Double conversions. | |
264 | * @deprecated Register replacement converters for Double.TYPE and | |
265 | * Double.class instead | |
266 | */ | |
267 | 195 | private Double defaultDouble = new Double(0.0); |
268 | ||
269 | /** | |
270 | * Gets the default value for Double conversions. | |
271 | * @return The default Double value | |
272 | * @deprecated Register replacement converters for Double.TYPE and | |
273 | * Double.class instead | |
274 | */ | |
275 | public double getDefaultDouble() { | |
276 | 0 | return (defaultDouble.doubleValue()); |
277 | } | |
278 | ||
279 | /** | |
280 | * Sets the default value for Double conversions. | |
281 | * @param newDefaultDouble The default Double value | |
282 | * @deprecated Register replacement converters for Double.TYPE and | |
283 | * Double.class instead | |
284 | */ | |
285 | public void setDefaultDouble(double newDefaultDouble) { | |
286 | 0 | defaultDouble = new Double(newDefaultDouble); |
287 | 0 | register(new DoubleConverter(defaultDouble), Double.TYPE); |
288 | 0 | register(new DoubleConverter(defaultDouble), Double.class); |
289 | 0 | } |
290 | ||
291 | ||
292 | /** | |
293 | * The default value for Float conversions. | |
294 | * @deprecated Register replacement converters for Float.TYPE and | |
295 | * Float.class instead | |
296 | */ | |
297 | 195 | private Float defaultFloat = new Float((float) 0.0); |
298 | ||
299 | /** | |
300 | * Gets the default value for Float conversions. | |
301 | * @return The default Float value | |
302 | * @deprecated Register replacement converters for Float.TYPE and | |
303 | * Float.class instead | |
304 | */ | |
305 | public float getDefaultFloat() { | |
306 | 0 | return (defaultFloat.floatValue()); |
307 | } | |
308 | ||
309 | /** | |
310 | * Sets the default value for Float conversions. | |
311 | * @param newDefaultFloat The default Float value | |
312 | * @deprecated Register replacement converters for Float.TYPE and | |
313 | * Float.class instead | |
314 | */ | |
315 | public void setDefaultFloat(float newDefaultFloat) { | |
316 | 0 | defaultFloat = new Float(newDefaultFloat); |
317 | 0 | register(new FloatConverter(defaultFloat), Float.TYPE); |
318 | 0 | register(new FloatConverter(defaultFloat), Float.class); |
319 | 0 | } |
320 | ||
321 | ||
322 | /** | |
323 | * The default value for Integer conversions. | |
324 | * @deprecated Register replacement converters for Integer.TYPE and | |
325 | * Integer.class instead | |
326 | */ | |
327 | 195 | private Integer defaultInteger = new Integer(0); |
328 | ||
329 | /** | |
330 | * Gets the default value for Integer conversions. | |
331 | * @return The default Integer value | |
332 | * @deprecated Register replacement converters for Integer.TYPE and | |
333 | * Integer.class instead | |
334 | */ | |
335 | public int getDefaultInteger() { | |
336 | 0 | return (defaultInteger.intValue()); |
337 | } | |
338 | ||
339 | /** | |
340 | * Sets the default value for Integer conversions. | |
341 | * @param newDefaultInteger The default Integer value | |
342 | * @deprecated Register replacement converters for Integer.TYPE and | |
343 | * Integer.class instead | |
344 | */ | |
345 | public void setDefaultInteger(int newDefaultInteger) { | |
346 | 0 | defaultInteger = new Integer(newDefaultInteger); |
347 | 0 | register(new IntegerConverter(defaultInteger), Integer.TYPE); |
348 | 0 | register(new IntegerConverter(defaultInteger), Integer.class); |
349 | 0 | } |
350 | ||
351 | ||
352 | /** | |
353 | * The default value for Long conversions. | |
354 | * @deprecated Register replacement converters for Long.TYPE and | |
355 | * Long.class instead | |
356 | */ | |
357 | 195 | private Long defaultLong = new Long(0); |
358 | ||
359 | /** | |
360 | * Gets the default value for Long conversions. | |
361 | * @return The default Long value | |
362 | * @deprecated Register replacement converters for Long.TYPE and | |
363 | * Long.class instead | |
364 | */ | |
365 | public long getDefaultLong() { | |
366 | 0 | return (defaultLong.longValue()); |
367 | } | |
368 | ||
369 | /** | |
370 | * Sets the default value for Long conversions. | |
371 | * @param newDefaultLong The default Long value | |
372 | * @deprecated Register replacement converters for Long.TYPE and | |
373 | * Long.class instead | |
374 | */ | |
375 | public void setDefaultLong(long newDefaultLong) { | |
376 | 0 | defaultLong = new Long(newDefaultLong); |
377 | 0 | register(new LongConverter(defaultLong), Long.TYPE); |
378 | 0 | register(new LongConverter(defaultLong), Long.class); |
379 | 0 | } |
380 | ||
381 | ||
382 | /** | |
383 | * The default value for Short conversions. | |
384 | * @deprecated Register replacement converters for Short.TYPE and | |
385 | * Short.class instead | |
386 | */ | |
387 | 1 | private static Short defaultShort = new Short((short) 0); |
388 | ||
389 | /** | |
390 | * Gets the default value for Short conversions. | |
391 | * @return The default Short value | |
392 | * @deprecated Register replacement converters for Short.TYPE and | |
393 | * Short.class instead | |
394 | */ | |
395 | public short getDefaultShort() { | |
396 | 0 | return (defaultShort.shortValue()); |
397 | } | |
398 | ||
399 | /** | |
400 | * Sets the default value for Short conversions. | |
401 | * @param newDefaultShort The default Short value | |
402 | * @deprecated Register replacement converters for Short.TYPE and | |
403 | * Short.class instead | |
404 | */ | |
405 | public void setDefaultShort(short newDefaultShort) { | |
406 | 0 | defaultShort = new Short(newDefaultShort); |
407 | 0 | register(new ShortConverter(defaultShort), Short.TYPE); |
408 | 0 | register(new ShortConverter(defaultShort), Short.class); |
409 | 0 | } |
410 | ||
411 | ||
412 | ||
413 | /** | |
414 | * Convert the specified value into a String. If the specified value | |
415 | * is an array, the first element (converted to a String) will be | |
416 | * returned. The registered {@link Converter} for the | |
417 | * <code>java.lang.String</code> class will be used, which allows | |
418 | * applications to customize Object->String conversions (the default | |
419 | * implementation simply uses toString()). | |
420 | * | |
421 | * @param value Value to be converted (may be null) | |
422 | * @return The converted String value | |
423 | */ | |
424 | public String convert(Object value) { | |
425 | ||
426 | 107 | if (value == null) { |
427 | 8 | return null; |
428 | 99 | } else if (value.getClass().isArray()) { |
429 | 10 | if (Array.getLength(value) < 1) { |
430 | 2 | return (null); |
431 | } | |
432 | 8 | value = Array.get(value, 0); |
433 | 8 | if (value == null) { |
434 | 0 | return null; |
435 | } else { | |
436 | 8 | Converter converter = lookup(String.class); |
437 | 8 | return ((String) converter.convert(String.class, value)); |
438 | } | |
439 | } else { | |
440 | 89 | Converter converter = lookup(String.class); |
441 | 89 | return ((String) converter.convert(String.class, value)); |
442 | } | |
443 | ||
444 | } | |
445 | ||
446 | ||
447 | /** | |
448 | * Convert the specified value to an object of the specified class (if | |
449 | * possible). Otherwise, return a String representation of the value. | |
450 | * | |
451 | * @param value Value to be converted (may be null) | |
452 | * @param clazz Java class to be converted to | |
453 | * @return The converted value | |
454 | * | |
455 | * @exception ConversionException if thrown by an underlying Converter | |
456 | */ | |
457 | public Object convert(String value, Class clazz) { | |
458 | ||
459 | 148 | if (log.isDebugEnabled()) { |
460 | 0 | log.debug("Convert string '" + value + "' to class '" + |
461 | clazz.getName() + "'"); | |
462 | } | |
463 | 148 | Converter converter = lookup(clazz); |
464 | 148 | if (converter == null) { |
465 | 3 | converter = lookup(String.class); |
466 | } | |
467 | 148 | if (log.isTraceEnabled()) { |
468 | 0 | log.trace(" Using converter " + converter); |
469 | } | |
470 | 148 | return (converter.convert(clazz, value)); |
471 | ||
472 | } | |
473 | ||
474 | ||
475 | /** | |
476 | * Convert an array of specified values to an array of objects of the | |
477 | * specified class (if possible). If the specified Java class is itself | |
478 | * an array class, this class will be the type of the returned value. | |
479 | * Otherwise, an array will be constructed whose component type is the | |
480 | * specified class. | |
481 | * | |
482 | * @param values Array of values to be converted | |
483 | * @param clazz Java array or element class to be converted to | |
484 | * @return The converted value | |
485 | * | |
486 | * @exception ConversionException if thrown by an underlying Converter | |
487 | */ | |
488 | public Object convert(String[] values, Class clazz) { | |
489 | ||
490 | 8 | Class type = clazz; |
491 | 8 | if (clazz.isArray()) { |
492 | 7 | type = clazz.getComponentType(); |
493 | } | |
494 | 8 | if (log.isDebugEnabled()) { |
495 | 0 | log.debug("Convert String[" + values.length + "] to class '" + |
496 | type.getName() + "[]'"); | |
497 | } | |
498 | 8 | Converter converter = lookup(type); |
499 | 8 | if (converter == null) { |
500 | 0 | converter = lookup(String.class); |
501 | } | |
502 | 8 | if (log.isTraceEnabled()) { |
503 | 0 | log.trace(" Using converter " + converter); |
504 | } | |
505 | 8 | Object array = Array.newInstance(type, values.length); |
506 | 26 | for (int i = 0; i < values.length; i++) { |
507 | 18 | Array.set(array, i, converter.convert(type, values[i])); |
508 | } | |
509 | 8 | return (array); |
510 | ||
511 | } | |
512 | ||
513 | ||
514 | /** | |
515 | * <p>Convert the value to an object of the specified class (if | |
516 | * possible).</p> | |
517 | * | |
518 | * @param value Value to be converted (may be null) | |
519 | * @param targetType Class of the value to be converted to | |
520 | * @return The converted value | |
521 | * | |
522 | * @exception ConversionException if thrown by an underlying Converter | |
523 | */ | |
524 | public Object convert(Object value, Class targetType) { | |
525 | ||
526 | 221 | Class sourceType = value == null ? null : value.getClass(); |
527 | ||
528 | 221 | if (log.isDebugEnabled()) { |
529 | 0 | if (value == null) { |
530 | 0 | log.debug("Convert null value to type '" + |
531 | targetType.getName() + "'"); | |
532 | } else { | |
533 | 0 | log.debug("Convert type '" + sourceType.getName() + "' value '" + value + |
534 | "' to type '" + targetType.getName() + "'"); | |
535 | } | |
536 | } | |
537 | ||
538 | 221 | Object converted = value; |
539 | 221 | Converter converter = lookup(sourceType, targetType); |
540 | 221 | if (converter != null) { |
541 | 215 | if (log.isTraceEnabled()) { |
542 | 0 | log.trace(" Using converter " + converter); |
543 | } | |
544 | 215 | converted = converter.convert(targetType, value); |
545 | } | |
546 | 221 | if (targetType == String.class && converted != null && |
547 | !(converted instanceof String)) { | |
548 | ||
549 | // NOTE: For backwards compatibility, if the Converter | |
550 | // doesn't handle conversion-->String then | |
551 | // use the registered String Converter | |
552 | 3 | converter = lookup(String.class); |
553 | 3 | if (converter != null) { |
554 | 2 | if (log.isTraceEnabled()) { |
555 | 0 | log.trace(" Using converter " + converter); |
556 | } | |
557 | 2 | converted = converter.convert(String.class, converted); |
558 | } | |
559 | ||
560 | // If the object still isn't a String, use toString() method | |
561 | 3 | if (converted != null && !(converted instanceof String)) { |
562 | 2 | converted = converted.toString(); |
563 | } | |
564 | ||
565 | } | |
566 | 221 | return converted; |
567 | ||
568 | } | |
569 | ||
570 | /** | |
571 | * Remove all registered {@link Converter}s, and re-establish the | |
572 | * standard Converters. | |
573 | */ | |
574 | public void deregister() { | |
575 | ||
576 | 356 | converters.clear(); |
577 | ||
578 | 356 | registerPrimitives(false); |
579 | 356 | registerStandard(false, false); |
580 | 356 | registerOther(true); |
581 | 356 | registerArrays(false, 0); |
582 | 356 | register(BigDecimal.class, new BigDecimalConverter()); |
583 | 356 | register(BigInteger.class, new BigIntegerConverter()); |
584 | 356 | } |
585 | ||
586 | /** | |
587 | * Register the provided converters with the specified defaults. | |
588 | * | |
589 | * @param throwException <code>true</code> if the converters should | |
590 | * throw an exception when a conversion error occurs, otherwise <code> | |
591 | * <code>false</code> if a default value should be used. | |
592 | * @param defaultNull <code>true</code>if the <i>standard</i> converters | |
593 | * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) | |
594 | * should use a default value of <code>null</code>, otherwise <code>false</code>. | |
595 | * N.B. This values is ignored if <code>throwException</code> is <code>true</code> | |
596 | * @param defaultArraySize The size of the default array value for array converters | |
597 | * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>). | |
598 | * Specifying a value less than zero causes a <code>null<code> value to be used for | |
599 | * the default. | |
600 | */ | |
601 | public void register(boolean throwException, boolean defaultNull, int defaultArraySize) { | |
602 | 0 | registerPrimitives(throwException); |
603 | 0 | registerStandard(throwException, defaultNull); |
604 | 0 | registerOther(throwException); |
605 | 0 | registerArrays(throwException, defaultArraySize); |
606 | 0 | } |
607 | ||
608 | /** | |
609 | * Register the converters for primitive types. | |
610 | * </p> | |
611 | * This method registers the following converters: | |
612 | * <ul> | |
613 | * <li><code>Boolean.TYPE</code> - {@link BooleanConverter}</li> | |
614 | * <li><code>Byte.TYPE</code> - {@link ByteConverter}</li> | |
615 | * <li><code>Character.TYPE</code> - {@link CharacterConverter}</li> | |
616 | * <li><code>Double.TYPE</code> - {@link DoubleConverter}</li> | |
617 | * <li><code>Float.TYPE</code> - {@link FloatConverter}</li> | |
618 | * <li><code>Integer.TYPE</code> - {@link IntegerConverter}</li> | |
619 | * <li><code>Long.TYPE</code> - {@link LongConverter}</li> | |
620 | * <li><code>Short.TYPE</code> - {@link ShortConverter}</li> | |
621 | * </ul> | |
622 | * @param throwException <code>true</code> if the converters should | |
623 | * throw an exception when a conversion error occurs, otherwise <code> | |
624 | * <code>false</code> if a default value should be used. | |
625 | */ | |
626 | private void registerPrimitives(boolean throwException) { | |
627 | 356 | register(Boolean.TYPE, throwException ? new BooleanConverter() : new BooleanConverter(Boolean.FALSE)); |
628 | 356 | register(Byte.TYPE, throwException ? new ByteConverter() : new ByteConverter(ZERO)); |
629 | 356 | register(Character.TYPE, throwException ? new CharacterConverter() : new CharacterConverter(SPACE)); |
630 | 356 | register(Double.TYPE, throwException ? new DoubleConverter() : new DoubleConverter(ZERO)); |
631 | 356 | register(Float.TYPE, throwException ? new FloatConverter() : new FloatConverter(ZERO)); |
632 | 356 | register(Integer.TYPE, throwException ? new IntegerConverter() : new IntegerConverter(ZERO)); |
633 | 356 | register(Long.TYPE, throwException ? new LongConverter() : new LongConverter(ZERO)); |
634 | 356 | register(Short.TYPE, throwException ? new ShortConverter() : new ShortConverter(ZERO)); |
635 | 356 | } |
636 | ||
637 | /** | |
638 | * Register the converters for standard types. | |
639 | * </p> | |
640 | * This method registers the following converters: | |
641 | * <ul> | |
642 | * <li><code>BigDecimal.class</code> - {@link BigDecimalConverter}</li> | |
643 | * <li><code>BigInteger.class</code> - {@link BigIntegerConverter}</li> | |
644 | * <li><code>Boolean.class</code> - {@link BooleanConverter}</li> | |
645 | * <li><code>Byte.class</code> - {@link ByteConverter}</li> | |
646 | * <li><code>Character.class</code> - {@link CharacterConverter}</li> | |
647 | * <li><code>Double.class</code> - {@link DoubleConverter}</li> | |
648 | * <li><code>Float.class</code> - {@link FloatConverter}</li> | |
649 | * <li><code>Integer.class</code> - {@link IntegerConverter}</li> | |
650 | * <li><code>Long.class</code> - {@link LongConverter}</li> | |
651 | * <li><code>Short.class</code> - {@link ShortConverter}</li> | |
652 | * <li><code>String.class</code> - {@link StringConverter}</li> | |
653 | * </ul> | |
654 | * @param throwException <code>true</code> if the converters should | |
655 | * throw an exception when a conversion error occurs, otherwise <code> | |
656 | * <code>false</code> if a default value should be used. | |
657 | * @param defaultNull <code>true</code>if the <i>standard</i> converters | |
658 | * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) | |
659 | * should use a default value of <code>null</code>, otherwise <code>false</code>. | |
660 | * N.B. This values is ignored if <code>throwException</code> is <code>true</code> | |
661 | */ | |
662 | private void registerStandard(boolean throwException, boolean defaultNull) { | |
663 | ||
664 | 356 | Number defaultNumber = defaultNull ? null : ZERO; |
665 | 356 | BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal("0.0"); |
666 | 356 | BigInteger bigIntDeflt = defaultNull ? null : new BigInteger("0"); |
667 | 356 | Boolean booleanDefault = defaultNull ? null : Boolean.FALSE; |
668 | 356 | Character charDefault = defaultNull ? null : SPACE; |
669 | 356 | String stringDefault = defaultNull ? null : ""; |
670 | ||
671 | 356 | register(BigDecimal.class, throwException ? new BigDecimalConverter() : new BigDecimalConverter(bigDecDeflt)); |
672 | 356 | register(BigInteger.class, throwException ? new BigIntegerConverter() : new BigIntegerConverter(bigIntDeflt)); |
673 | 356 | register(Boolean.class, throwException ? new BooleanConverter() : new BooleanConverter(booleanDefault)); |
674 | 356 | register(Byte.class, throwException ? new ByteConverter() : new ByteConverter(defaultNumber)); |
675 | 356 | register(Character.class, throwException ? new CharacterConverter() : new CharacterConverter(charDefault)); |
676 | 356 | register(Double.class, throwException ? new DoubleConverter() : new DoubleConverter(defaultNumber)); |
677 | 356 | register(Float.class, throwException ? new FloatConverter() : new FloatConverter(defaultNumber)); |
678 | 356 | register(Integer.class, throwException ? new IntegerConverter() : new IntegerConverter(defaultNumber)); |
679 | 356 | register(Long.class, throwException ? new LongConverter() : new LongConverter(defaultNumber)); |
680 | 356 | register(Short.class, throwException ? new ShortConverter() : new ShortConverter(defaultNumber)); |
681 | 356 | register(String.class, throwException ? new StringConverter() : new StringConverter(stringDefault)); |
682 | ||
683 | 356 | } |
684 | ||
685 | /** | |
686 | * Register the converters for other types. | |
687 | * </p> | |
688 | * This method registers the following converters: | |
689 | * <ul> | |
690 | * <li><code>Class.class</code> - {@link ClassConverter}</li> | |
691 | * <li><code>java.util.Date.class</code> - {@link DateConverter}</li> | |
692 | * <li><code>java.util.Calendar.class</code> - {@link CalendarConverter}</li> | |
693 | * <li><code>File.class</code> - {@link FileConverter}</li> | |
694 | * <li><code>java.sql.Date.class</code> - {@link SqlDateConverter}</li> | |
695 | * <li><code>java.sql.Time.class</code> - {@link SqlTimeConverter}</li> | |
696 | * <li><code>java.sql.Timestamp.class</code> - {@link SqlTimestampConverter}</li> | |
697 | * <li><code>URL.class</code> - {@link URLConverter}</li> | |
698 | * </ul> | |
699 | * @param throwException <code>true</code> if the converters should | |
700 | * throw an exception when a conversion error occurs, otherwise <code> | |
701 | * <code>false</code> if a default value should be used. | |
702 | */ | |
703 | private void registerOther(boolean throwException) { | |
704 | 356 | register(Class.class, throwException ? new ClassConverter() : new ClassConverter(null)); |
705 | 356 | register(java.util.Date.class, throwException ? new DateConverter() : new DateConverter(null)); |
706 | 356 | register(Calendar.class, throwException ? new CalendarConverter() : new CalendarConverter(null)); |
707 | 356 | register(File.class, throwException ? new FileConverter() : new FileConverter(null)); |
708 | 356 | register(java.sql.Date.class, throwException ? new SqlDateConverter() : new SqlDateConverter(null)); |
709 | 356 | register(java.sql.Time.class, throwException ? new SqlTimeConverter() : new SqlTimeConverter(null)); |
710 | 356 | register(Timestamp.class, throwException ? new SqlTimestampConverter() : new SqlTimestampConverter(null)); |
711 | 356 | register(URL.class, throwException ? new URLConverter() : new URLConverter(null)); |
712 | 356 | } |
713 | ||
714 | /** | |
715 | * Register array converters. | |
716 | * | |
717 | * @param throwException <code>true</code> if the converters should | |
718 | * throw an exception when a conversion error occurs, otherwise <code> | |
719 | * <code>false</code> if a default value should be used. | |
720 | * @param defaultArraySize The size of the default array value for array converters | |
721 | * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>). | |
722 | * Specifying a value less than zero causes a <code>null<code> value to be used for | |
723 | * the default. | |
724 | */ | |
725 | private void registerArrays(boolean throwException, int defaultArraySize) { | |
726 | ||
727 | // Primitives | |
728 | 356 | registerArrayConverter(Boolean.TYPE, new BooleanConverter(), throwException, defaultArraySize); |
729 | 356 | registerArrayConverter(Byte.TYPE, new ByteConverter(), throwException, defaultArraySize); |
730 | 356 | registerArrayConverter(Character.TYPE, new CharacterConverter(), throwException, defaultArraySize); |
731 | 356 | registerArrayConverter(Double.TYPE, new DoubleConverter(), throwException, defaultArraySize); |
732 | 356 | registerArrayConverter(Float.TYPE, new FloatConverter(), throwException, defaultArraySize); |
733 | 356 | registerArrayConverter(Integer.TYPE, new IntegerConverter(), throwException, defaultArraySize); |
734 | 356 | registerArrayConverter(Long.TYPE, new LongConverter(), throwException, defaultArraySize); |
735 | 356 | registerArrayConverter(Short.TYPE, new ShortConverter(), throwException, defaultArraySize); |
736 | ||
737 | // Standard | |
738 | 356 | registerArrayConverter(BigDecimal.class, new BigDecimalConverter(), throwException, defaultArraySize); |
739 | 356 | registerArrayConverter(BigInteger.class, new BigIntegerConverter(), throwException, defaultArraySize); |
740 | 356 | registerArrayConverter(Boolean.class, new BooleanConverter(), throwException, defaultArraySize); |
741 | 356 | registerArrayConverter(Byte.class, new ByteConverter(), throwException, defaultArraySize); |
742 | 356 | registerArrayConverter(Character.class, new CharacterConverter(), throwException, defaultArraySize); |
743 | 356 | registerArrayConverter(Double.class, new DoubleConverter(), throwException, defaultArraySize); |
744 | 356 | registerArrayConverter(Float.class, new FloatConverter(), throwException, defaultArraySize); |
745 | 356 | registerArrayConverter(Integer.class, new IntegerConverter(), throwException, defaultArraySize); |
746 | 356 | registerArrayConverter(Long.class, new LongConverter(), throwException, defaultArraySize); |
747 | 356 | registerArrayConverter(Short.class, new ShortConverter(), throwException, defaultArraySize); |
748 | 356 | registerArrayConverter(String.class, new StringConverter(), throwException, defaultArraySize); |
749 | ||
750 | // Other | |
751 | 356 | registerArrayConverter(Class.class, new ClassConverter(), throwException, defaultArraySize); |
752 | 356 | registerArrayConverter(java.util.Date.class, new DateConverter(), throwException, defaultArraySize); |
753 | 356 | registerArrayConverter(Calendar.class, new DateConverter(), throwException, defaultArraySize); |
754 | 356 | registerArrayConverter(File.class, new FileConverter(), throwException, defaultArraySize); |
755 | 356 | registerArrayConverter(java.sql.Date.class, new SqlDateConverter(), throwException, defaultArraySize); |
756 | 356 | registerArrayConverter(java.sql.Time.class, new SqlTimeConverter(), throwException, defaultArraySize); |
757 | 356 | registerArrayConverter(Timestamp.class, new SqlTimestampConverter(), throwException, defaultArraySize); |
758 | 356 | registerArrayConverter(URL.class, new URLConverter(), throwException, defaultArraySize); |
759 | ||
760 | 356 | } |
761 | ||
762 | /** | |
763 | * Register a new ArrayConverter with the specified element delegate converter | |
764 | * that returns a default array of the specified size in the event of conversion errors. | |
765 | * | |
766 | * @param componentType The component type of the array | |
767 | * @param componentConverter The converter to delegate to for the array elements | |
768 | * @param throwException Whether a conversion exception should be thrown or a default | |
769 | * value used in the event of a conversion error | |
770 | * @param defaultArraySize The size of the default array | |
771 | */ | |
772 | private void registerArrayConverter(Class componentType, Converter componentConverter, | |
773 | boolean throwException, int defaultArraySize) { | |
774 | 9612 | Class arrayType = Array.newInstance(componentType, 0).getClass(); |
775 | 9612 | Converter arrayConverter = null; |
776 | 9612 | if (throwException) { |
777 | 0 | arrayConverter = new ArrayConverter(arrayType, componentConverter); |
778 | } else { | |
779 | 9612 | arrayConverter = new ArrayConverter(arrayType, componentConverter, defaultArraySize); |
780 | } | |
781 | 9612 | register(arrayType, arrayConverter); |
782 | 9612 | } |
783 | ||
784 | /** strictly for convenience since it has same parameter order as Map.put */ | |
785 | private void register(Class clazz, Converter converter) { | |
786 | 19936 | register(new ConverterFacade(converter), clazz); |
787 | 19936 | } |
788 | ||
789 | /** | |
790 | * Remove any registered {@link Converter} for the specified destination | |
791 | * <code>Class</code>. | |
792 | * | |
793 | * @param clazz Class for which to remove a registered Converter | |
794 | */ | |
795 | public void deregister(Class clazz) { | |
796 | ||
797 | 3 | converters.remove(clazz); |
798 | ||
799 | 3 | } |
800 | ||
801 | ||
802 | /** | |
803 | * Look up and return any registered {@link Converter} for the specified | |
804 | * destination class; if there is no registered Converter, return | |
805 | * <code>null</code>. | |
806 | * | |
807 | * @param clazz Class for which to return a registered Converter | |
808 | * @return The registered {@link Converter} or <code>null</code> if not found | |
809 | */ | |
810 | public Converter lookup(Class clazz) { | |
811 | ||
812 | 716 | return ((Converter) converters.get(clazz)); |
813 | ||
814 | } | |
815 | ||
816 | /** | |
817 | * Look up and return any registered {@link Converter} for the specified | |
818 | * source and destination class; if there is no registered Converter, | |
819 | * return <code>null</code>. | |
820 | * | |
821 | * @param sourceType Class of the value being converted | |
822 | * @param targetType Class of the value to be converted to | |
823 | * @return The registered {@link Converter} or <code>null</code> if not found | |
824 | */ | |
825 | public Converter lookup(Class sourceType, Class targetType) { | |
826 | ||
827 | 221 | if (targetType == null) { |
828 | 0 | throw new IllegalArgumentException("Target type is missing"); |
829 | } | |
830 | 221 | if (sourceType == null) { |
831 | 18 | return lookup(targetType); |
832 | } | |
833 | ||
834 | 203 | Converter converter = null; |
835 | // Convert --> String | |
836 | 203 | if (targetType == String.class) { |
837 | 67 | converter = lookup(sourceType); |
838 | 67 | if (converter == null && (sourceType.isArray() || |
839 | Collection.class.isAssignableFrom(sourceType))) { | |
840 | 1 | converter = lookup(String[].class); |
841 | } | |
842 | 67 | if (converter == null) { |
843 | 6 | converter = lookup(String.class); |
844 | } | |
845 | 67 | return converter; |
846 | } | |
847 | ||
848 | // Convert --> String array | |
849 | 136 | if (targetType == String[].class) { |
850 | 15 | if (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType)) { |
851 | 9 | converter = lookup(sourceType); |
852 | } | |
853 | 15 | if (converter == null) { |
854 | 6 | converter = lookup(String[].class); |
855 | } | |
856 | 15 | return converter; |
857 | } | |
858 | ||
859 | 121 | return lookup(targetType); |
860 | ||
861 | } | |
862 | ||
863 | /** | |
864 | * Register a custom {@link Converter} for the specified destination | |
865 | * <code>Class</code>, replacing any previously registered Converter. | |
866 | * | |
867 | * @param converter Converter to be registered | |
868 | * @param clazz Destination class for conversions performed by this | |
869 | * Converter | |
870 | */ | |
871 | public void register(Converter converter, Class clazz) { | |
872 | ||
873 | 20169 | converters.put(clazz, converter); |
874 | ||
875 | 20169 | } |
876 | } |