001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.beanutils;
019:
020: import java.io.File;
021: import java.lang.reflect.Array;
022: import java.math.BigDecimal;
023: import java.math.BigInteger;
024: import java.net.URL;
025: import java.sql.Timestamp;
026: import java.util.Calendar;
027: import java.util.Collection;
028: import java.util.Map;
029: import java.util.HashMap;
030: import org.apache.commons.beanutils.converters.ArrayConverter;
031: import org.apache.commons.beanutils.converters.BigDecimalConverter;
032: import org.apache.commons.beanutils.converters.BigIntegerConverter;
033: import org.apache.commons.beanutils.converters.BooleanConverter;
034: import org.apache.commons.beanutils.converters.ByteConverter;
035: import org.apache.commons.beanutils.converters.CalendarConverter;
036: import org.apache.commons.beanutils.converters.CharacterConverter;
037: import org.apache.commons.beanutils.converters.ClassConverter;
038: import org.apache.commons.beanutils.converters.ConverterFacade;
039: import org.apache.commons.beanutils.converters.DateConverter;
040: import org.apache.commons.beanutils.converters.DoubleConverter;
041: import org.apache.commons.beanutils.converters.FileConverter;
042: import org.apache.commons.beanutils.converters.FloatConverter;
043: import org.apache.commons.beanutils.converters.IntegerConverter;
044: import org.apache.commons.beanutils.converters.LongConverter;
045: import org.apache.commons.beanutils.converters.ShortConverter;
046: import org.apache.commons.beanutils.converters.SqlDateConverter;
047: import org.apache.commons.beanutils.converters.SqlTimeConverter;
048: import org.apache.commons.beanutils.converters.SqlTimestampConverter;
049: import org.apache.commons.beanutils.converters.StringConverter;
050: import org.apache.commons.beanutils.converters.URLConverter;
051: import org.apache.commons.logging.Log;
052: import org.apache.commons.logging.LogFactory;
053:
054: /**
055: * <p>Utility methods for converting String scalar values to objects of the
056: * specified Class, String arrays to arrays of the specified Class. The
057: * actual {@link Converter} instance to be used can be registered for each
058: * possible destination Class. Unless you override them, standard
059: * {@link Converter} instances are provided for all of the following
060: * destination Classes:</p>
061: * <ul>
062: * <li>java.lang.BigDecimal (no default value)</li>
063: * <li>java.lang.BigInteger (no default value)</li>
064: * <li>boolean and java.lang.Boolean (default to false)</li>
065: * <li>byte and java.lang.Byte (default to zero)</li>
066: * <li>char and java.lang.Character (default to a space)</li>
067: * <li>java.lang.Class (no default value)</li>
068: * <li>double and java.lang.Double (default to zero)</li>
069: * <li>float and java.lang.Float (default to zero)</li>
070: * <li>int and java.lang.Integer (default to zero)</li>
071: * <li>long and java.lang.Long (default to zero)</li>
072: * <li>short and java.lang.Short (default to zero)</li>
073: * <li>java.lang.String (default to null)</li>
074: * <li>java.io.File (no default value)</li>
075: * <li>java.net.URL (no default value)</li>
076: * <li>java.sql.Date (no default value)</li>
077: * <li>java.sql.Time (no default value)</li>
078: * <li>java.sql.Timestamp (no default value)</li>
079: * </ul>
080: *
081: * <p>For backwards compatibility, the standard Converters for primitive
082: * types (and the corresponding wrapper classes) return a defined
083: * default value when a conversion error occurs. If you prefer to have a
084: * {@link ConversionException} thrown instead, replace the standard Converter
085: * instances with instances created with the zero-arguments constructor. For
086: * example, to cause the Converters for integers to throw an exception on
087: * conversion errors, you could do this:</p>
088: * <pre>
089: * // No-args constructor gets the version that throws exceptions
090: * Converter myConverter =
091: * new org.apache.commons.beanutils.converter.IntegerConverter();
092: * ConvertUtils.register(myConverter, Integer.TYPE); // Native type
093: * ConvertUtils.register(myConverter, Integer.class); // Wrapper class
094: * </pre>
095: *
096: * <p>
097: * Converters generally treat null input as if it were invalid
098: * input, ie they return their default value if one was specified when the
099: * converter was constructed, and throw an exception otherwise. If you prefer
100: * nulls to be preserved for converters that are converting to objects (not
101: * primitives) then register a converter as above, passing a default value of
102: * null to the converter constructor (and of course registering that converter
103: * only for the .class target).
104: * </p>
105: *
106: * <p>
107: * When a converter is listed above as having no default value, then that
108: * converter will throw an exception when passed null or an invalid value
109: * as its input. In particular, by default the BigInteger and BigDecimal
110: * converters have no default (and are therefore somewhat inconsistent
111: * with the other numerical converters which all have zero as their default).
112: * </p>
113: *
114: * <p>
115: * Converters that generate <i>arrays</i> of each of the primitive types are
116: * also automatically configured (including String[]). When passed null
117: * or invalid input, these return an empty array (not null). See class
118: * AbstractArrayConverter for the supported input formats for these converters.
119: * </p>
120: *
121: * @author Craig R. McClanahan
122: * @author Ralph Schaer
123: * @author Chris Audley
124: * @author James Strachan
125: * @version $Revision: 557868 $ $Date: 2007-07-20 06:22:19 +0100 (Fri, 20 Jul 2007) $
126: * @since 1.7
127: */
128:
129: public class ConvertUtilsBean {
130:
131: private static final Integer ZERO = new Integer(0);
132: private static final Character SPACE = new Character(' ');
133:
134: // ------------------------------------------------------- Class Methods
135: /**
136: * Get singleton instance
137: * @return The singleton instance
138: */
139: protected static ConvertUtilsBean getInstance() {
140: return BeanUtilsBean.getInstance().getConvertUtils();
141: }
142:
143: // ------------------------------------------------------- Variables
144:
145: /**
146: * The set of {@link Converter}s that can be used to convert Strings
147: * into objects of a specified Class, keyed by the destination Class.
148: */
149: private Map converters = new HashMap();
150:
151: /**
152: * The <code>Log</code> instance for this class.
153: */
154: private Log log = LogFactory.getLog(ConvertUtils.class);
155:
156: // ------------------------------------------------------- Constructors
157:
158: /** Construct a bean with standard converters registered */
159: public ConvertUtilsBean() {
160: deregister();
161: }
162:
163: // --------------------------------------------------------- Public Methods
164:
165: /**
166: * The default value for Boolean conversions.
167: * @deprecated Register replacement converters for Boolean.TYPE and
168: * Boolean.class instead
169: */
170: private Boolean defaultBoolean = Boolean.FALSE;
171:
172: /**
173: * Gets the default value for Boolean conversions.
174: * @return The default Boolean value
175: * @deprecated Register replacement converters for Boolean.TYPE and
176: * Boolean.class instead
177: */
178: public boolean getDefaultBoolean() {
179: return (defaultBoolean.booleanValue());
180: }
181:
182: /**
183: * Sets the default value for Boolean conversions.
184: * @param newDefaultBoolean The default Boolean value
185: * @deprecated Register replacement converters for Boolean.TYPE and
186: * Boolean.class instead
187: */
188: public void setDefaultBoolean(boolean newDefaultBoolean) {
189: defaultBoolean = (newDefaultBoolean ? Boolean.TRUE
190: : Boolean.FALSE);
191: register(new BooleanConverter(defaultBoolean), Boolean.TYPE);
192: register(new BooleanConverter(defaultBoolean), Boolean.class);
193: }
194:
195: /**
196: * The default value for Byte conversions.
197: * @deprecated Register replacement converters for Byte.TYPE and
198: * Byte.class instead
199: */
200: private Byte defaultByte = new Byte((byte) 0);
201:
202: /**
203: * Gets the default value for Byte conversions.
204: * @return The default Byte value
205: * @deprecated Register replacement converters for Byte.TYPE and
206: * Byte.class instead
207: */
208: public byte getDefaultByte() {
209: return (defaultByte.byteValue());
210: }
211:
212: /**
213: * Sets the default value for Byte conversions.
214: * @param newDefaultByte The default Byte value
215: * @deprecated Register replacement converters for Byte.TYPE and
216: * Byte.class instead
217: */
218: public void setDefaultByte(byte newDefaultByte) {
219: defaultByte = new Byte(newDefaultByte);
220: register(new ByteConverter(defaultByte), Byte.TYPE);
221: register(new ByteConverter(defaultByte), Byte.class);
222: }
223:
224: /**
225: * The default value for Character conversions.
226: * @deprecated Register replacement converters for Character.TYPE and
227: * Character.class instead
228: */
229: private Character defaultCharacter = new Character(' ');
230:
231: /**
232: * Gets the default value for Character conversions.
233: * @return The default Character value
234: * @deprecated Register replacement converters for Character.TYPE and
235: * Character.class instead
236: */
237: public char getDefaultCharacter() {
238: return (defaultCharacter.charValue());
239: }
240:
241: /**
242: * Sets the default value for Character conversions.
243: * @param newDefaultCharacter The default Character value
244: * @deprecated Register replacement converters for Character.TYPE and
245: * Character.class instead
246: */
247: public void setDefaultCharacter(char newDefaultCharacter) {
248: defaultCharacter = new Character(newDefaultCharacter);
249: register(new CharacterConverter(defaultCharacter),
250: Character.TYPE);
251: register(new CharacterConverter(defaultCharacter),
252: Character.class);
253: }
254:
255: /**
256: * The default value for Double conversions.
257: * @deprecated Register replacement converters for Double.TYPE and
258: * Double.class instead
259: */
260: private Double defaultDouble = new Double(0.0);
261:
262: /**
263: * Gets the default value for Double conversions.
264: * @return The default Double value
265: * @deprecated Register replacement converters for Double.TYPE and
266: * Double.class instead
267: */
268: public double getDefaultDouble() {
269: return (defaultDouble.doubleValue());
270: }
271:
272: /**
273: * Sets the default value for Double conversions.
274: * @param newDefaultDouble The default Double value
275: * @deprecated Register replacement converters for Double.TYPE and
276: * Double.class instead
277: */
278: public void setDefaultDouble(double newDefaultDouble) {
279: defaultDouble = new Double(newDefaultDouble);
280: register(new DoubleConverter(defaultDouble), Double.TYPE);
281: register(new DoubleConverter(defaultDouble), Double.class);
282: }
283:
284: /**
285: * The default value for Float conversions.
286: * @deprecated Register replacement converters for Float.TYPE and
287: * Float.class instead
288: */
289: private Float defaultFloat = new Float((float) 0.0);
290:
291: /**
292: * Gets the default value for Float conversions.
293: * @return The default Float value
294: * @deprecated Register replacement converters for Float.TYPE and
295: * Float.class instead
296: */
297: public float getDefaultFloat() {
298: return (defaultFloat.floatValue());
299: }
300:
301: /**
302: * Sets the default value for Float conversions.
303: * @param newDefaultFloat The default Float value
304: * @deprecated Register replacement converters for Float.TYPE and
305: * Float.class instead
306: */
307: public void setDefaultFloat(float newDefaultFloat) {
308: defaultFloat = new Float(newDefaultFloat);
309: register(new FloatConverter(defaultFloat), Float.TYPE);
310: register(new FloatConverter(defaultFloat), Float.class);
311: }
312:
313: /**
314: * The default value for Integer conversions.
315: * @deprecated Register replacement converters for Integer.TYPE and
316: * Integer.class instead
317: */
318: private Integer defaultInteger = new Integer(0);
319:
320: /**
321: * Gets the default value for Integer conversions.
322: * @return The default Integer value
323: * @deprecated Register replacement converters for Integer.TYPE and
324: * Integer.class instead
325: */
326: public int getDefaultInteger() {
327: return (defaultInteger.intValue());
328: }
329:
330: /**
331: * Sets the default value for Integer conversions.
332: * @param newDefaultInteger The default Integer value
333: * @deprecated Register replacement converters for Integer.TYPE and
334: * Integer.class instead
335: */
336: public void setDefaultInteger(int newDefaultInteger) {
337: defaultInteger = new Integer(newDefaultInteger);
338: register(new IntegerConverter(defaultInteger), Integer.TYPE);
339: register(new IntegerConverter(defaultInteger), Integer.class);
340: }
341:
342: /**
343: * The default value for Long conversions.
344: * @deprecated Register replacement converters for Long.TYPE and
345: * Long.class instead
346: */
347: private Long defaultLong = new Long(0);
348:
349: /**
350: * Gets the default value for Long conversions.
351: * @return The default Long value
352: * @deprecated Register replacement converters for Long.TYPE and
353: * Long.class instead
354: */
355: public long getDefaultLong() {
356: return (defaultLong.longValue());
357: }
358:
359: /**
360: * Sets the default value for Long conversions.
361: * @param newDefaultLong The default Long value
362: * @deprecated Register replacement converters for Long.TYPE and
363: * Long.class instead
364: */
365: public void setDefaultLong(long newDefaultLong) {
366: defaultLong = new Long(newDefaultLong);
367: register(new LongConverter(defaultLong), Long.TYPE);
368: register(new LongConverter(defaultLong), Long.class);
369: }
370:
371: /**
372: * The default value for Short conversions.
373: * @deprecated Register replacement converters for Short.TYPE and
374: * Short.class instead
375: */
376: private static Short defaultShort = new Short((short) 0);
377:
378: /**
379: * Gets the default value for Short conversions.
380: * @return The default Short value
381: * @deprecated Register replacement converters for Short.TYPE and
382: * Short.class instead
383: */
384: public short getDefaultShort() {
385: return (defaultShort.shortValue());
386: }
387:
388: /**
389: * Sets the default value for Short conversions.
390: * @param newDefaultShort The default Short value
391: * @deprecated Register replacement converters for Short.TYPE and
392: * Short.class instead
393: */
394: public void setDefaultShort(short newDefaultShort) {
395: defaultShort = new Short(newDefaultShort);
396: register(new ShortConverter(defaultShort), Short.TYPE);
397: register(new ShortConverter(defaultShort), Short.class);
398: }
399:
400: /**
401: * Convert the specified value into a String. If the specified value
402: * is an array, the first element (converted to a String) will be
403: * returned. The registered {@link Converter} for the
404: * <code>java.lang.String</code> class will be used, which allows
405: * applications to customize Object->String conversions (the default
406: * implementation simply uses toString()).
407: *
408: * @param value Value to be converted (may be null)
409: * @return The converted String value
410: */
411: public String convert(Object value) {
412:
413: if (value == null) {
414: return ((String) null);
415: } else if (value.getClass().isArray()) {
416: if (Array.getLength(value) < 1) {
417: return (null);
418: }
419: value = Array.get(value, 0);
420: if (value == null) {
421: return ((String) null);
422: } else {
423: Converter converter = lookup(String.class);
424: return ((String) converter.convert(String.class, value));
425: }
426: } else {
427: Converter converter = lookup(String.class);
428: return ((String) converter.convert(String.class, value));
429: }
430:
431: }
432:
433: /**
434: * Convert the specified value to an object of the specified class (if
435: * possible). Otherwise, return a String representation of the value.
436: *
437: * @param value Value to be converted (may be null)
438: * @param clazz Java class to be converted to
439: * @return The converted value
440: *
441: * @exception ConversionException if thrown by an underlying Converter
442: */
443: public Object convert(String value, Class clazz) {
444:
445: if (log.isDebugEnabled()) {
446: log.debug("Convert string '" + value + "' to class '"
447: + clazz.getName() + "'");
448: }
449: Converter converter = lookup(clazz);
450: if (converter == null) {
451: converter = lookup(String.class);
452: }
453: if (log.isTraceEnabled()) {
454: log.trace(" Using converter " + converter);
455: }
456: return (converter.convert(clazz, value));
457:
458: }
459:
460: /**
461: * Convert an array of specified values to an array of objects of the
462: * specified class (if possible). If the specified Java class is itself
463: * an array class, this class will be the type of the returned value.
464: * Otherwise, an array will be constructed whose component type is the
465: * specified class.
466: *
467: * @param values Array of values to be converted
468: * @param clazz Java array or element class to be converted to
469: * @return The converted value
470: *
471: * @exception ConversionException if thrown by an underlying Converter
472: */
473: public Object convert(String[] values, Class clazz) {
474:
475: Class type = clazz;
476: if (clazz.isArray()) {
477: type = clazz.getComponentType();
478: }
479: if (log.isDebugEnabled()) {
480: log.debug("Convert String[" + values.length
481: + "] to class '" + type.getName() + "[]'");
482: }
483: Converter converter = lookup(type);
484: if (converter == null) {
485: converter = lookup(String.class);
486: }
487: if (log.isTraceEnabled()) {
488: log.trace(" Using converter " + converter);
489: }
490: Object array = Array.newInstance(type, values.length);
491: for (int i = 0; i < values.length; i++) {
492: Array.set(array, i, converter.convert(type, values[i]));
493: }
494: return (array);
495:
496: }
497:
498: /**
499: * <p>Convert the value to an object of the specified class (if
500: * possible).</p>
501: *
502: * @param value Value to be converted (may be null)
503: * @param targetType Class of the value to be converted to
504: * @return The converted value
505: *
506: * @exception ConversionException if thrown by an underlying Converter
507: */
508: public Object convert(Object value, Class targetType) {
509:
510: Class sourceType = value == null ? null : value.getClass();
511:
512: if (log.isDebugEnabled()) {
513: if (value == null) {
514: log.debug("Convert null value to type '"
515: + targetType.getName() + "'");
516: } else {
517: log.debug("Convert type '" + sourceType.getName()
518: + "' value '" + value + "' to type '"
519: + targetType.getName() + "'");
520: }
521: }
522:
523: Object converted = value;
524: Converter converter = lookup(sourceType, targetType);
525: if (converter != null) {
526: if (log.isTraceEnabled()) {
527: log.trace(" Using converter " + converter);
528: }
529: converted = converter.convert(targetType, value);
530: }
531: if (targetType == String.class && converted != null
532: && !(converted instanceof String)) {
533:
534: // NOTE: For backwards compatibility, if the Converter
535: // doesn't handle conversion-->String then
536: // use the registered String Converter
537: converter = lookup(String.class);
538: if (converter != null) {
539: if (log.isTraceEnabled()) {
540: log.trace(" Using converter " + converter);
541: }
542: converted = converter.convert(String.class, converted);
543: }
544:
545: // If the object still isn't a String, use toString() method
546: if (converted != null && !(converted instanceof String)) {
547: converted = converted.toString();
548: }
549:
550: }
551: return converted;
552:
553: }
554:
555: /**
556: * Remove all registered {@link Converter}s, and re-establish the
557: * standard Converters.
558: */
559: public void deregister() {
560:
561: converters.clear();
562:
563: registerPrimitives(false);
564: registerStandard(false, false);
565: registerOther(true);
566: registerArrays(false, 0);
567: register(BigDecimal.class, new BigDecimalConverter());
568: register(BigInteger.class, new BigIntegerConverter());
569: }
570:
571: /**
572: * Register the provided converters with the specified defaults.
573: *
574: * @param throwException <code>true</code> if the converters should
575: * throw an exception when a conversion error occurs, otherwise <code>
576: * <code>false</code> if a default value should be used.
577: * @param defaultNull <code>true</code>if the <i>standard</i> converters
578: * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)})
579: * should use a default value of <code>null</code>, otherwise <code>false</code>.
580: * N.B. This values is ignored if <code>throwException</code> is <code>true</code>
581: * @param defaultArraySize The size of the default array value for array converters
582: * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>).
583: * Specifying a value less than zero causes a <code>null<code> value to be used for
584: * the default.
585: */
586: public void register(boolean throwException, boolean defaultNull,
587: int defaultArraySize) {
588: registerPrimitives(throwException);
589: registerStandard(throwException, defaultNull);
590: registerOther(throwException);
591: registerArrays(throwException, defaultArraySize);
592: }
593:
594: /**
595: * Register the converters for primitive types.
596: * </p>
597: * This method registers the following converters:
598: * <ul>
599: * <li><code>Boolean.TYPE</code> - {@link BooleanConverter}</li>
600: * <li><code>Byte.TYPE</code> - {@link ByteConverter}</li>
601: * <li><code>Character.TYPE</code> - {@link CharacterConverter}</li>
602: * <li><code>Double.TYPE</code> - {@link DoubleConverter}</li>
603: * <li><code>Float.TYPE</code> - {@link FloatConverter}</li>
604: * <li><code>Integer.TYPE</code> - {@link IntegerConverter}</li>
605: * <li><code>Long.TYPE</code> - {@link LongConverter}</li>
606: * <li><code>Short.TYPE</code> - {@link ShortConverter}</li>
607: * </ul>
608: * @param throwException <code>true</code> if the converters should
609: * throw an exception when a conversion error occurs, otherwise <code>
610: * <code>false</code> if a default value should be used.
611: */
612: private void registerPrimitives(boolean throwException) {
613: register(Boolean.TYPE, throwException ? new BooleanConverter()
614: : new BooleanConverter(Boolean.FALSE));
615: register(Byte.TYPE, throwException ? new ByteConverter()
616: : new ByteConverter(ZERO));
617: register(Character.TYPE,
618: throwException ? new CharacterConverter()
619: : new CharacterConverter(SPACE));
620: register(Double.TYPE, throwException ? new DoubleConverter()
621: : new DoubleConverter(ZERO));
622: register(Float.TYPE, throwException ? new FloatConverter()
623: : new FloatConverter(ZERO));
624: register(Integer.TYPE, throwException ? new IntegerConverter()
625: : new IntegerConverter(ZERO));
626: register(Long.TYPE, throwException ? new LongConverter()
627: : new LongConverter(ZERO));
628: register(Short.TYPE, throwException ? new ShortConverter()
629: : new ShortConverter(ZERO));
630: }
631:
632: /**
633: * Register the converters for standard types.
634: * </p>
635: * This method registers the following converters:
636: * <ul>
637: * <li><code>BigDecimal.class</code> - {@link BigDecimalConverter}</li>
638: * <li><code>BigInteger.class</code> - {@link BigIntegerConverter}</li>
639: * <li><code>Boolean.class</code> - {@link BooleanConverter}</li>
640: * <li><code>Byte.class</code> - {@link ByteConverter}</li>
641: * <li><code>Character.class</code> - {@link CharacterConverter}</li>
642: * <li><code>Double.class</code> - {@link DoubleConverter}</li>
643: * <li><code>Float.class</code> - {@link FloatConverter}</li>
644: * <li><code>Integer.class</code> - {@link IntegerConverter}</li>
645: * <li><code>Long.class</code> - {@link LongConverter}</li>
646: * <li><code>Short.class</code> - {@link ShortConverter}</li>
647: * <li><code>String.class</code> - {@link StringConverter}</li>
648: * </ul>
649: * @param throwException <code>true</code> if the converters should
650: * throw an exception when a conversion error occurs, otherwise <code>
651: * <code>false</code> if a default value should be used.
652: * @param defaultNull <code>true</code>if the <i>standard</i> converters
653: * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)})
654: * should use a default value of <code>null</code>, otherwise <code>false</code>.
655: * N.B. This values is ignored if <code>throwException</code> is <code>true</code>
656: */
657: private void registerStandard(boolean throwException,
658: boolean defaultNull) {
659:
660: Number defaultNumber = defaultNull ? null : ZERO;
661: BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal(
662: "0.0");
663: BigInteger bigIntDeflt = defaultNull ? null : new BigInteger(
664: "0");
665: Boolean booleanDefault = defaultNull ? null : Boolean.FALSE;
666: Character charDefault = defaultNull ? null : SPACE;
667: String stringDefault = defaultNull ? null : "";
668:
669: register(BigDecimal.class,
670: throwException ? new BigDecimalConverter()
671: : new BigDecimalConverter(bigDecDeflt));
672: register(BigInteger.class,
673: throwException ? new BigIntegerConverter()
674: : new BigIntegerConverter(bigIntDeflt));
675: register(Boolean.class, throwException ? new BooleanConverter()
676: : new BooleanConverter(booleanDefault));
677: register(Byte.class, throwException ? new ByteConverter()
678: : new ByteConverter(defaultNumber));
679: register(Character.class,
680: throwException ? new CharacterConverter()
681: : new CharacterConverter(charDefault));
682: register(Double.class, throwException ? new DoubleConverter()
683: : new DoubleConverter(defaultNumber));
684: register(Float.class, throwException ? new FloatConverter()
685: : new FloatConverter(defaultNumber));
686: register(Integer.class, throwException ? new IntegerConverter()
687: : new IntegerConverter(defaultNumber));
688: register(Long.class, throwException ? new LongConverter()
689: : new LongConverter(defaultNumber));
690: register(Short.class, throwException ? new ShortConverter()
691: : new ShortConverter(defaultNumber));
692: register(String.class, throwException ? new StringConverter()
693: : new StringConverter(stringDefault));
694:
695: }
696:
697: /**
698: * Register the converters for other types.
699: * </p>
700: * This method registers the following converters:
701: * <ul>
702: * <li><code>Class.class</code> - {@link ClassConverter}</li>
703: * <li><code>java.util.Date.class</code> - {@link DateConverter}</li>
704: * <li><code>java.util.Calendar.class</code> - {@link CalendarConverter}</li>
705: * <li><code>File.class</code> - {@link FileConverter}</li>
706: * <li><code>java.sql.Date.class</code> - {@link SqlDateConverter}</li>
707: * <li><code>java.sql.Time.class</code> - {@link SqlTimeConverter}</li>
708: * <li><code>java.sql.Timestamp.class</code> - {@link SqlTimestampConverter}</li>
709: * <li><code>URL.class</code> - {@link URLConverter}</li>
710: * </ul>
711: * @param throwException <code>true</code> if the converters should
712: * throw an exception when a conversion error occurs, otherwise <code>
713: * <code>false</code> if a default value should be used.
714: */
715: private void registerOther(boolean throwException) {
716: register(Class.class, throwException ? new ClassConverter()
717: : new ClassConverter(null));
718: register(java.util.Date.class,
719: throwException ? new DateConverter()
720: : new DateConverter(null));
721: register(Calendar.class,
722: throwException ? new CalendarConverter()
723: : new CalendarConverter(null));
724: register(File.class, throwException ? new FileConverter()
725: : new FileConverter(null));
726: register(java.sql.Date.class,
727: throwException ? new SqlDateConverter()
728: : new SqlDateConverter(null));
729: register(java.sql.Time.class,
730: throwException ? new SqlTimeConverter()
731: : new SqlTimeConverter(null));
732: register(Timestamp.class,
733: throwException ? new SqlTimestampConverter()
734: : new SqlTimestampConverter(null));
735: register(URL.class, throwException ? new URLConverter()
736: : new URLConverter(null));
737: }
738:
739: /**
740: * Register array converters.
741: *
742: * @param throwException <code>true</code> if the converters should
743: * throw an exception when a conversion error occurs, otherwise <code>
744: * <code>false</code> if a default value should be used.
745: * @param defaultArraySize The size of the default array value for array converters
746: * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>).
747: * Specifying a value less than zero causes a <code>null<code> value to be used for
748: * the default.
749: */
750: private void registerArrays(boolean throwException,
751: int defaultArraySize) {
752:
753: // Primitives
754: registerArrayConverter(Boolean.TYPE, new BooleanConverter(),
755: throwException, defaultArraySize);
756: registerArrayConverter(Byte.TYPE, new ByteConverter(),
757: throwException, defaultArraySize);
758: registerArrayConverter(Character.TYPE,
759: new CharacterConverter(), throwException,
760: defaultArraySize);
761: registerArrayConverter(Double.TYPE, new DoubleConverter(),
762: throwException, defaultArraySize);
763: registerArrayConverter(Float.TYPE, new FloatConverter(),
764: throwException, defaultArraySize);
765: registerArrayConverter(Integer.TYPE, new IntegerConverter(),
766: throwException, defaultArraySize);
767: registerArrayConverter(Long.TYPE, new LongConverter(),
768: throwException, defaultArraySize);
769: registerArrayConverter(Short.TYPE, new ShortConverter(),
770: throwException, defaultArraySize);
771:
772: // Standard
773: registerArrayConverter(BigDecimal.class,
774: new BigDecimalConverter(), throwException,
775: defaultArraySize);
776: registerArrayConverter(BigInteger.class,
777: new BigIntegerConverter(), throwException,
778: defaultArraySize);
779: registerArrayConverter(Boolean.class, new BooleanConverter(),
780: throwException, defaultArraySize);
781: registerArrayConverter(Byte.class, new ByteConverter(),
782: throwException, defaultArraySize);
783: registerArrayConverter(Character.class,
784: new CharacterConverter(), throwException,
785: defaultArraySize);
786: registerArrayConverter(Double.class, new DoubleConverter(),
787: throwException, defaultArraySize);
788: registerArrayConverter(Float.class, new FloatConverter(),
789: throwException, defaultArraySize);
790: registerArrayConverter(Integer.class, new IntegerConverter(),
791: throwException, defaultArraySize);
792: registerArrayConverter(Long.class, new LongConverter(),
793: throwException, defaultArraySize);
794: registerArrayConverter(Short.class, new ShortConverter(),
795: throwException, defaultArraySize);
796: registerArrayConverter(String.class, new StringConverter(),
797: throwException, defaultArraySize);
798:
799: // Other
800: registerArrayConverter(Class.class, new ClassConverter(),
801: throwException, defaultArraySize);
802: registerArrayConverter(java.util.Date.class,
803: new DateConverter(), throwException, defaultArraySize);
804: registerArrayConverter(Calendar.class, new DateConverter(),
805: throwException, defaultArraySize);
806: registerArrayConverter(File.class, new FileConverter(),
807: throwException, defaultArraySize);
808: registerArrayConverter(java.sql.Date.class,
809: new SqlDateConverter(), throwException,
810: defaultArraySize);
811: registerArrayConverter(java.sql.Time.class,
812: new SqlTimeConverter(), throwException,
813: defaultArraySize);
814: registerArrayConverter(Timestamp.class,
815: new SqlTimestampConverter(), throwException,
816: defaultArraySize);
817: registerArrayConverter(URL.class, new URLConverter(),
818: throwException, defaultArraySize);
819:
820: }
821:
822: /**
823: * Register a new ArrayConverter with the specified element delegate converter
824: * that returns a default array of the specified size in the event of conversion errors.
825: *
826: * @param componentType The component type of the array
827: * @param componentConverter The converter to delegate to for the array elements
828: * @param throwException Whether a conversion exception should be thrown or a default
829: * value used in the event of a conversion error
830: * @param defaultArraySize The size of the default array
831: */
832: private void registerArrayConverter(Class componentType,
833: Converter componentConverter, boolean throwException,
834: int defaultArraySize) {
835: Class arrayType = Array.newInstance(componentType, 0)
836: .getClass();
837: Converter arrayConverter = null;
838: if (throwException) {
839: arrayConverter = new ArrayConverter(arrayType,
840: componentConverter);
841: } else {
842: arrayConverter = new ArrayConverter(arrayType,
843: componentConverter, defaultArraySize);
844: }
845: register(arrayType, arrayConverter);
846: }
847:
848: /** strictly for convenience since it has same parameter order as Map.put */
849: private void register(Class clazz, Converter converter) {
850: register(new ConverterFacade(converter), clazz);
851: }
852:
853: /**
854: * Remove any registered {@link Converter} for the specified destination
855: * <code>Class</code>.
856: *
857: * @param clazz Class for which to remove a registered Converter
858: */
859: public void deregister(Class clazz) {
860:
861: converters.remove(clazz);
862:
863: }
864:
865: /**
866: * Look up and return any registered {@link Converter} for the specified
867: * destination class; if there is no registered Converter, return
868: * <code>null</code>.
869: *
870: * @param clazz Class for which to return a registered Converter
871: * @return The registered {@link Converter} or <code>null</code> if not found
872: */
873: public Converter lookup(Class clazz) {
874:
875: return ((Converter) converters.get(clazz));
876:
877: }
878:
879: /**
880: * Look up and return any registered {@link Converter} for the specified
881: * source and destination class; if there is no registered Converter,
882: * return <code>null</code>.
883: *
884: * @param sourceType Class of the value being converted
885: * @param targetType Class of the value to be converted to
886: * @return The registered {@link Converter} or <code>null</code> if not found
887: */
888: public Converter lookup(Class sourceType, Class targetType) {
889:
890: if (targetType == null) {
891: throw new IllegalArgumentException("Target type is missing");
892: }
893: if (sourceType == null) {
894: return lookup(targetType);
895: }
896:
897: Converter converter = null;
898: // Convert --> String
899: if (targetType == String.class) {
900: converter = lookup(sourceType);
901: if (converter == null
902: && (sourceType.isArray() || Collection.class
903: .isAssignableFrom(sourceType))) {
904: converter = lookup(String[].class);
905: }
906: if (converter == null) {
907: converter = lookup(String.class);
908: }
909: return converter;
910: }
911:
912: // Convert --> String array
913: if (targetType == String[].class) {
914: if (sourceType.isArray()
915: || Collection.class.isAssignableFrom(sourceType)) {
916: converter = lookup(sourceType);
917: }
918: if (converter == null) {
919: converter = lookup(String[].class);
920: }
921: return converter;
922: }
923:
924: return lookup(targetType);
925:
926: }
927:
928: /**
929: * Register a custom {@link Converter} for the specified destination
930: * <code>Class</code>, replacing any previously registered Converter.
931: *
932: * @param converter Converter to be registered
933: * @param clazz Destination class for conversions performed by this
934: * Converter
935: */
936: public void register(Converter converter, Class clazz) {
937:
938: converters.put(clazz, converter);
939:
940: }
941: }
|