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