| 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 | } |