View Javadoc
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  package org.apache.commons.beanutils2;
19  
20  import java.awt.Color;
21  import java.awt.Dimension;
22  import java.awt.Point;
23  import java.io.File;
24  import java.lang.reflect.Array;
25  import java.math.BigDecimal;
26  import java.math.BigInteger;
27  import java.net.InetAddress;
28  import java.net.URI;
29  import java.net.URL;
30  import java.nio.file.Path;
31  import java.sql.Timestamp;
32  import java.time.Duration;
33  import java.time.LocalDate;
34  import java.time.LocalDateTime;
35  import java.time.LocalTime;
36  import java.time.MonthDay;
37  import java.time.OffsetDateTime;
38  import java.time.OffsetTime;
39  import java.time.Period;
40  import java.time.Year;
41  import java.time.YearMonth;
42  import java.time.ZoneId;
43  import java.time.ZoneOffset;
44  import java.time.ZonedDateTime;
45  import java.util.Calendar;
46  import java.util.Collection;
47  import java.util.Locale;
48  import java.util.Map;
49  import java.util.Objects;
50  import java.util.UUID;
51  import java.util.regex.Pattern;
52  
53  import org.apache.commons.beanutils2.converters.ArrayConverter;
54  import org.apache.commons.beanutils2.converters.BigDecimalConverter;
55  import org.apache.commons.beanutils2.converters.BigIntegerConverter;
56  import org.apache.commons.beanutils2.converters.BooleanConverter;
57  import org.apache.commons.beanutils2.converters.ByteConverter;
58  import org.apache.commons.beanutils2.converters.CalendarConverter;
59  import org.apache.commons.beanutils2.converters.CharacterConverter;
60  import org.apache.commons.beanutils2.converters.ClassConverter;
61  import org.apache.commons.beanutils2.converters.ColorConverter;
62  import org.apache.commons.beanutils2.converters.ConverterFacade;
63  import org.apache.commons.beanutils2.converters.DateConverter;
64  import org.apache.commons.beanutils2.converters.DimensionConverter;
65  import org.apache.commons.beanutils2.converters.DoubleConverter;
66  import org.apache.commons.beanutils2.converters.DurationConverter;
67  import org.apache.commons.beanutils2.converters.EnumConverter;
68  import org.apache.commons.beanutils2.converters.FileConverter;
69  import org.apache.commons.beanutils2.converters.FloatConverter;
70  import org.apache.commons.beanutils2.converters.InetAddressConverter;
71  import org.apache.commons.beanutils2.converters.IntegerConverter;
72  import org.apache.commons.beanutils2.converters.LocalDateConverter;
73  import org.apache.commons.beanutils2.converters.LocalDateTimeConverter;
74  import org.apache.commons.beanutils2.converters.LocalTimeConverter;
75  import org.apache.commons.beanutils2.converters.LocaleConverter;
76  import org.apache.commons.beanutils2.converters.LongConverter;
77  import org.apache.commons.beanutils2.converters.MonthDayConverter;
78  import org.apache.commons.beanutils2.converters.OffsetDateTimeConverter;
79  import org.apache.commons.beanutils2.converters.OffsetTimeConverter;
80  import org.apache.commons.beanutils2.converters.PathConverter;
81  import org.apache.commons.beanutils2.converters.PatternConverter;
82  import org.apache.commons.beanutils2.converters.PeriodConverter;
83  import org.apache.commons.beanutils2.converters.PointConverter;
84  import org.apache.commons.beanutils2.converters.ShortConverter;
85  import org.apache.commons.beanutils2.converters.StringConverter;
86  import org.apache.commons.beanutils2.converters.URIConverter;
87  import org.apache.commons.beanutils2.converters.URLConverter;
88  import org.apache.commons.beanutils2.converters.UUIDConverter;
89  import org.apache.commons.beanutils2.converters.YearConverter;
90  import org.apache.commons.beanutils2.converters.YearMonthConverter;
91  import org.apache.commons.beanutils2.converters.ZoneIdConverter;
92  import org.apache.commons.beanutils2.converters.ZoneOffsetConverter;
93  import org.apache.commons.beanutils2.converters.ZonedDateTimeConverter;
94  import org.apache.commons.beanutils2.sql.converters.SqlDateConverter;
95  import org.apache.commons.beanutils2.sql.converters.SqlTimeConverter;
96  import org.apache.commons.beanutils2.sql.converters.SqlTimestampConverter;
97  import org.apache.commons.logging.Log;
98  import org.apache.commons.logging.LogFactory;
99  
100 /**
101  * TODO DOCS
102  * <p>
103  * 2.0
104  * </p>
105  *
106  * {@link ConvertUtilsBean} implementation that delegates {@code convert()} methods to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
107  *
108  * <p>
109  * To configure this implementation for the current context ClassLoader invoke {@code BeanUtilsBean.setInstance(new BeanUtilsBean2());}
110  * </p>
111  *
112  * <p>
113  * Pre-2.0
114  * </p>
115  *
116  * <p>
117  * Utility methods for converting String scalar values to objects of the specified Class, String arrays to arrays of the specified Class. The actual
118  * {@link Converter} instance to be used can be registered for each possible destination Class. Unless you override them, standard {@link Converter} instances
119  * are provided for all of the following destination Classes:
120  * </p>
121  * <ul>
122  * <li>java.lang.BigDecimal (no default value)</li>
123  * <li>java.lang.BigInteger (no default value)</li>
124  * <li>boolean and java.lang.Boolean (default to false)</li>
125  * <li>byte and java.lang.Byte (default to zero)</li>
126  * <li>char and java.lang.Character (default to a space)</li>
127  * <li>java.lang.Class (no default value)</li>
128  * <li>java.awt.Color (no default value)</li>
129  * <li>java.awt.Dimension (no default value)</li>
130  * <li>double and java.lang.Double (default to zero)</li>
131  * <li>float and java.lang.Float (default to zero)</li>
132  * <li>int and java.lang.Integer (default to zero)</li>
133  * <li>long and java.lang.Long (default to zero)</li>
134  * <li>short and java.lang.Short (default to zero)</li>
135  * <li>java.lang.String (default to null)</li>
136  * <li>java.lang.Enum (default to null)</li>
137  * <li>java.io.File (no default value)</li>
138  * <li>java.net.InetAddress (no default value)</li>
139  * <li>java.util.Locale (no default value)</li>
140  * <li>java.nio.file.Path (no default value)</li>
141  * <li>java.net.URL (no default value)</li>
142  * <li>java.net.URI (no default value)</li>
143  * <li>java.util.UUID (no default value)</li>
144  * <li>java.sql.Date (no default value)</li>
145  * <li>java.sql.Time (no default value)</li>
146  * <li>java.sql.Timestamp (no default value)</li>
147  * <li>java.time.LocalDate (no default value)</li>
148  * <li>java.time.LocalDateTime (no default value)</li>
149  * <li>java.time.LocalTime (no default value)</li>
150  * <li>java.time.OffsetDateTime (no default value)</li>
151  * <li>java.time.OffsetTime (no default value)</li>
152  * <li>java.time.ZonedDateTime (no default value)</li>
153  * <li>java.time.Duration (no default value)</li>
154  * <li>java.time.MonthDay (no default value)</li>
155  * <li>java.util.regex.Pattern (no default value)</li>
156  * <li>java.time.Period (no default value)</li>
157  * <li>java.awt.Point (no default value)</li>
158  * <li>java.time.Year (no default value)</li>
159  * <li>java.time.YearMonth (no default value)</li>
160  * <li>java.time.ZoneId (no default value)</li>
161  * <li>java.time.ZoneOffset (no default value)</li>
162  * </ul>
163  *
164  * <p>
165  * For backwards compatibility, the standard Converters for primitive types (and the corresponding wrapper classes) return a defined default value when a
166  * conversion error occurs. If you prefer to have a {@link ConversionException} thrown instead, replace the standard Converter instances with instances created
167  * with the zero-arguments constructor. For example, to cause the Converters for integers to throw an exception on conversion errors, you could do this:
168  * </p>
169  *
170  * <pre>
171  * // No-args constructor gets the version that throws exceptions
172  * Converter myConverter = new org.apache.commons.beanutils2.converter.IntegerConverter();
173  * ConvertUtils.register(myConverter, Integer.TYPE); // Native type
174  * ConvertUtils.register(myConverter, Integer.class); // Wrapper class
175  * </pre>
176  *
177  * <p>
178  * Converters generally treat null input as if it were invalid input, that is, they return their default value if one was specified when the converter was
179  * constructed, and throw an exception otherwise. If you prefer nulls to be preserved for converters that are converting to objects (not primitives) then
180  * register a converter as above, passing a default value of null to the converter constructor (and of course registering that converter only for the .class
181  * target).
182  * </p>
183  *
184  * <p>
185  * When a converter is listed above as having no default value, then that converter will throw an exception when passed null or an invalid value as its input.
186  * In particular, by default the BigInteger and BigDecimal converters have no default (and are therefore somewhat inconsistent with the other numerical
187  * converters which all have zero as their default).
188  * </p>
189  *
190  * <p>
191  * Converters that generate <em>arrays</em> of each of the primitive types are also automatically configured (including String[]). When passed null or invalid
192  * input, these return an empty array (not null). See class AbstractArrayConverter for the supported input formats for these converters.
193  * </p>
194  *
195  * @since 1.7
196  */
197 public class ConvertUtilsBean {
198 
199     private static final Integer ZERO = Integer.valueOf(0);
200     private static final Character SPACE = Character.valueOf(' ');
201 
202     /**
203      * The {@code Log} instance for this class.
204      */
205     private static final Log LOG = LogFactory.getLog(ConvertUtilsBean.class);
206 
207     /**
208      * Gets singleton instance
209      *
210      * @return The singleton instance
211      */
212     protected static ConvertUtilsBean getInstance() {
213         return BeanUtilsBean.getInstance().getConvertUtils();
214     }
215 
216     /**
217      * The set of {@link Converter}s that can be used to convert Strings into objects of a specified Class, keyed by the destination Class.
218      */
219     private final Map<Class<?>, Converter<?>> converters = BeanUtils.createCache();
220 
221     /** Constructs a bean with standard converters registered */
222     public ConvertUtilsBean() {
223         deregister();
224     }
225 
226     /**
227      * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
228      *
229      * @param value Value to be converted (may be null)
230      * @return The converted String value or null if value is null
231      * @see ConvertUtilsBean#convert(String[], Class)
232      */
233     public String convert(final Object value) {
234         return (String) convert(value, String.class);
235     }
236 
237     /**
238      * Converts the value to an object of the specified class (if possible). If no converter for the desired target type is registered, the passed in object is
239      * returned unchanged.
240      *
241      * @param <T>        The Class type.
242      * @param value      Value to be converted (may be null)
243      * @param targetType Class of the value to be converted to (must not be null)
244      * @return The converted value
245      * @throws ConversionException if thrown by an underlying Converter
246      */
247     public <T> Object convert(final Object value, final Class<T> targetType) {
248         final boolean nullValue = value == null;
249         final Class<?> sourceType = nullValue ? null : value.getClass();
250 
251         if (LOG.isDebugEnabled()) {
252             if (nullValue) {
253                 LOG.debug("Convert null value to type '" + targetType.getName() + "'");
254             } else {
255                 LOG.debug("Convert type '" + sourceType.getName() + "' value '" + value + "' to type '" + targetType.getName() + "'");
256             }
257         }
258 
259         Object converted = value;
260         final Converter<T> converter = lookup(sourceType, targetType);
261         if (converter != null) {
262             if (LOG.isTraceEnabled()) {
263                 LOG.trace("  Using converter " + converter);
264             }
265             converted = converter.convert(targetType, value);
266         }
267         if (String.class.equals(targetType) && converted != null && !(converted instanceof String)) {
268 
269             // NOTE: For backwards compatibility, if the Converter
270             // doesn't handle conversion-->String then
271             // use the registered String Converter
272             final Converter<String> strConverter = lookup(String.class);
273             if (strConverter != null) {
274                 if (LOG.isTraceEnabled()) {
275                     LOG.trace("  Using converter " + converter);
276                 }
277                 converted = strConverter.convert(String.class, converted);
278             }
279 
280             // If the object still isn't a String, use toString() method
281             if (converted != null && !(converted instanceof String)) {
282                 converted = converted.toString();
283             }
284 
285         }
286         return converted;
287     }
288 
289     /**
290      * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
291      *
292      * @param <R> the type of the class for the return value.
293      * @param value Value to be converted (may be null)
294      * @param clazz Java class to be converted to (must not be null)
295      * @return The converted value or null if value is null
296      * @see ConvertUtilsBean#convert(String[], Class)
297      */
298     public <R> Object convert(final String value, final Class<R> clazz) {
299         return convert((Object) value, clazz);
300     }
301 
302     /**
303      * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
304      *
305      * @param <T> the type of the class for the return value.
306      * @param value Array of values to be converted
307      * @param clazz Java array or element class to be converted to (must not be null)
308      * @return The converted value
309      * @see ConvertUtilsBean#convert(String[], Class)
310      */
311     public <T> Object convert(final String[] value, final Class<T> clazz) {
312         return convert((Object) value, clazz);
313     }
314 
315     private <T> Object convert(final String[] values, final Class<T> type, final Converter<T> converter) {
316         if (LOG.isTraceEnabled()) {
317             LOG.trace("  Using converter " + converter);
318         }
319         final Object array = Array.newInstance(type, values.length);
320         for (int i = 0; i < values.length; i++) {
321             Array.set(array, i, converter.convert(type, values[i]));
322         }
323         return array;
324     }
325 
326     /**
327      * Deregisters all registered {@link Converter}s, and re-establish the standard Converters.
328      */
329     public void deregister() {
330 
331         converters.clear();
332 
333         registerPrimitives(false);
334         registerStandard(false, false);
335         registerOther(true);
336         registerArrays(false, 0);
337         register(BigDecimal.class, new BigDecimalConverter());
338         register(BigInteger.class, new BigIntegerConverter());
339     }
340 
341     /**
342      * Remove any registered {@link Converter} for the specified destination {@code Class}.
343      *
344      * @param clazz Class for which to remove a registered Converter
345      */
346     public void deregister(final Class<?> clazz) {
347         converters.remove(clazz);
348     }
349 
350     /**
351      * Looks up and return any registered {@link Converter} for the specified source and destination class; if there is no registered Converter, return
352      * {@code null}.
353      *
354      * @param <T>        The converter type.
355      * @param sourceType Class of the value being converted
356      * @param targetType Class of the value to be converted to
357      * @return The registered {@link Converter} or {@code null} if not found
358      */
359     public <T> Converter<T> lookup(final Class<?> sourceType, final Class<T> targetType) {
360         Objects.requireNonNull(targetType, "targetType");
361         if (sourceType == null) {
362             return lookup(targetType);
363         }
364         Converter converter = null;
365         // Convert --> String
366         if (targetType == String.class) {
367             converter = lookup(sourceType);
368             if (converter == null && (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType))) {
369                 converter = lookup(String[].class);
370             }
371             if (converter == null) {
372                 converter = lookup(String.class);
373             }
374             return converter;
375         }
376 
377         // Convert --> String array
378         if (targetType == String[].class) {
379             if (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType)) {
380                 converter = lookup(sourceType);
381             }
382             if (converter == null) {
383                 converter = lookup(String[].class);
384             }
385             return converter;
386         }
387 
388         return lookup(targetType);
389 
390     }
391 
392     /**
393      * Looks up and return any registered {@link Converter} for the specified destination class; if there is no registered Converter, return {@code null}.
394      *
395      * @param <T>   The converter type.
396      * @param clazz Class for which to return a registered Converter
397      * @return The registered {@link Converter} or {@code null} if not found
398      */
399     @SuppressWarnings("unchecked")
400     public <T> Converter<T> lookup(final Class<T> clazz) {
401         return (Converter<T>) converters.get(clazz);
402     }
403 
404     /**
405      * Registers the provided converters with the specified defaults.
406      *
407      * @param throwException   {@code true} if the converters should throw an exception when a conversion error occurs, otherwise {@code false} if a default
408      *                         value should be used.
409      * @param defaultNull      {@code true}if the <em>standard</em> converters (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) should use a
410      *                         default value of {@code null</code>, otherwise <code>false}.
411      * N.B. This values is ignored if {@code throwException</code> is <code>true}
412      * @param defaultArraySize The size of the default array value for array converters
413      * (N.B. This values is ignored if {@code throwException</code> is <code>true}). Specifying a value less than zero causes a {@code null} value to be used
414      * for the default.
415      */
416     public void register(final boolean throwException, final boolean defaultNull, final int defaultArraySize) {
417         registerPrimitives(throwException);
418         registerStandard(throwException, defaultNull);
419         registerOther(throwException);
420         registerArrays(throwException, defaultArraySize);
421     }
422 
423     /** Strictly for convenience since it has same parameter order as Map.put */
424     private <T> void register(final Class<?> clazz, final Converter<T> converter) {
425         register(new ConverterFacade<>(converter), clazz);
426     }
427 
428     /**
429      * Registers a custom {@link Converter} for the specified destination {@code Class}, replacing any previously registered Converter.
430      *
431      * @param converter Converter to be registered
432      * @param clazz     Destination class for conversions performed by this Converter
433      */
434     public void register(final Converter converter, final Class<?> clazz) {
435         converters.put(clazz, converter);
436     }
437 
438     /**
439      * Registers a new ArrayConverter with the specified element delegate converter that returns a default array of the specified size in the event of
440      * conversion errors.
441      *
442      * @param componentType      The component type of the array
443      * @param componentConverter The converter to delegate to for the array elements
444      * @param throwException     Whether a conversion exception should be thrown or a default value used in the event of a conversion error
445      * @param defaultArraySize   The size of the default array
446      */
447     private <T> void registerArrayConverter(final Class<T> componentType, final Converter<T> componentConverter, final boolean throwException,
448             final int defaultArraySize) {
449         final Class<T[]> arrayType = (Class<T[]>) Array.newInstance(componentType, 0).getClass();
450         final Converter<T[]> arrayConverter;
451         if (throwException) {
452             arrayConverter = new ArrayConverter<>(arrayType, componentConverter);
453         } else {
454             arrayConverter = new ArrayConverter<>(arrayType, componentConverter, defaultArraySize);
455         }
456         register(arrayType, arrayConverter);
457     }
458 
459     /**
460      * Registers array converters.
461      *
462      * @param throwException   {@code true} if the converters should throw an exception when a conversion error occurs, otherwise {@code false} if a default
463      *                         value should be used.
464      * @param defaultArraySize The size of the default array value for array converters (N.B. This values is ignored if
465      *                         {@code throwException</code> is <code>true}). Specifying a value less than zero causes a {@code null} value to be used for the
466      *                         default.
467      */
468     private void registerArrays(final boolean throwException, final int defaultArraySize) {
469         // @formatter:off
470 
471         // Primitives
472         registerArrayConverter(Boolean.TYPE,   new BooleanConverter(),   throwException, defaultArraySize);
473         registerArrayConverter(Byte.TYPE,      new ByteConverter(),      throwException, defaultArraySize);
474         registerArrayConverter(Character.TYPE, new CharacterConverter(), throwException, defaultArraySize);
475         registerArrayConverter(Double.TYPE,    new DoubleConverter(),    throwException, defaultArraySize);
476         registerArrayConverter(Float.TYPE,     new FloatConverter(),     throwException, defaultArraySize);
477         registerArrayConverter(Integer.TYPE,   new IntegerConverter(),   throwException, defaultArraySize);
478         registerArrayConverter(Long.TYPE,      new LongConverter(),      throwException, defaultArraySize);
479         registerArrayConverter(Short.TYPE,     new ShortConverter(),     throwException, defaultArraySize);
480 
481         // Standard
482         registerArrayConverter(BigDecimal.class, new BigDecimalConverter(), throwException, defaultArraySize);
483         registerArrayConverter(BigInteger.class, new BigIntegerConverter(), throwException, defaultArraySize);
484         registerArrayConverter(Boolean.class,    new BooleanConverter(),    throwException, defaultArraySize);
485         registerArrayConverter(Byte.class,       new ByteConverter(),       throwException, defaultArraySize);
486         registerArrayConverter(Character.class,  new CharacterConverter(),  throwException, defaultArraySize);
487         registerArrayConverter(Double.class,     new DoubleConverter(),     throwException, defaultArraySize);
488         registerArrayConverter(Float.class,      new FloatConverter(),      throwException, defaultArraySize);
489         registerArrayConverter(Integer.class,    new IntegerConverter(),    throwException, defaultArraySize);
490         registerArrayConverter(Long.class,       new LongConverter(),       throwException, defaultArraySize);
491         registerArrayConverter(Short.class,      new ShortConverter(),      throwException, defaultArraySize);
492         registerArrayConverter(String.class,     new StringConverter(),     throwException, defaultArraySize);
493 
494         // Other
495         registerArrayConverter(Class.class,          new ClassConverter(),         throwException, defaultArraySize);
496         registerArrayConverter(Color.class,          new ColorConverter(),         throwException, defaultArraySize);
497         registerArrayConverter(Enum.class,           new EnumConverter(),          throwException, defaultArraySize);
498         registerArrayConverter(java.util.Date.class, new DateConverter(),          throwException, defaultArraySize);
499         registerArrayConverter(Calendar.class,       new CalendarConverter(),      throwException, defaultArraySize);
500         registerArrayConverter(Dimension.class,      new DimensionConverter(),     throwException, defaultArraySize);
501         registerArrayConverter(File.class,           new FileConverter(),          throwException, defaultArraySize);
502         registerArrayConverter(InetAddress.class,    new InetAddressConverter(),   throwException, defaultArraySize);
503         registerArrayConverter(Path.class,           new PathConverter(),          throwException, defaultArraySize);
504         registerArrayConverter(java.sql.Date.class,  new SqlDateConverter(),       throwException, defaultArraySize);
505         registerArrayConverter(java.sql.Time.class,  new SqlTimeConverter(),       throwException, defaultArraySize);
506         registerArrayConverter(Timestamp.class,      new SqlTimestampConverter(),  throwException, defaultArraySize);
507         registerArrayConverter(URL.class,            new URLConverter(),           throwException, defaultArraySize);
508         registerArrayConverter(URI.class,            new URIConverter(),           throwException, defaultArraySize);
509         registerArrayConverter(UUID.class,           new UUIDConverter(),          throwException, defaultArraySize);
510         registerArrayConverter(LocalDate.class,      new LocalDateConverter(),     throwException, defaultArraySize);
511         registerArrayConverter(LocalDateTime.class,  new LocalDateTimeConverter(), throwException, defaultArraySize);
512         registerArrayConverter(LocalTime.class,      new LocalTimeConverter(),     throwException, defaultArraySize);
513         registerArrayConverter(Locale.class,         new LocaleConverter(),        throwException, defaultArraySize);
514         registerArrayConverter(OffsetDateTime.class, new OffsetDateTimeConverter(),throwException, defaultArraySize);
515         registerArrayConverter(OffsetTime.class,     new OffsetTimeConverter(),    throwException, defaultArraySize);
516         registerArrayConverter(ZonedDateTime.class,  new ZonedDateTimeConverter(), throwException, defaultArraySize);
517         registerArrayConverter(Duration.class,       new DurationConverter(),      throwException, defaultArraySize);
518         registerArrayConverter(MonthDay.class,       new MonthDayConverter(),      throwException, defaultArraySize);
519         registerArrayConverter(Pattern.class,        new PatternConverter(),       throwException, defaultArraySize);
520         registerArrayConverter(Period.class,         new PeriodConverter(),        throwException, defaultArraySize);
521         registerArrayConverter(Point.class,          new PointConverter(),         throwException, defaultArraySize);
522         registerArrayConverter(Year.class,           new YearConverter(),          throwException, defaultArraySize);
523         registerArrayConverter(YearMonth.class,      new YearMonthConverter(),     throwException, defaultArraySize);
524         registerArrayConverter(ZoneId.class,         new ZoneIdConverter(),        throwException, defaultArraySize);
525         registerArrayConverter(ZoneOffset.class,     new ZoneOffsetConverter(),    throwException, defaultArraySize);
526         // @formatter:on
527     }
528 
529     /**
530      * Registers the converters for other types.
531      * </p>
532      * This method registers the following converters:
533      * <ul>
534      * <li>{@code Class.class} - {@link ClassConverter}</li>
535      * <li>{@code Enum.class} - {@link EnumConverter}</li>
536      * <li>{@code java.util.Date.class} - {@link DateConverter}</li>
537      * <li>{@code java.util.Calendar.class} - {@link CalendarConverter}</li>
538      * <li>{@code File.class} - {@link FileConverter}</li>
539      * <li>{@code Path.class} - {@link PathConverter}</li>
540      * <li>{@code java.sql.Date.class} - {@link SqlDateConverter}</li>
541      * <li>{@code java.sql.Time.class} - {@link SqlTimeConverter}</li>
542      * <li>{@code java.sql.Timestamp.class} - {@link SqlTimestampConverter}</li>
543      * <li>{@code URL.class} - {@link URLConverter}</li>
544      * <li>{@code URI.class} - {@link URIConverter}</li>
545      * <li>{@code UUID.class} - {@link UUIDConverter}</li>
546      * <li>{@code LocalDate.class} - {@link LocalDateConverter}</li>
547      * <li>{@code LocalDateTime.class} - {@link LocalDateTimeConverter}</li>
548      * <li>{@code LocalTime.class} - {@link LocalTimeConverter}</li>
549      * <li>{@code OffsetDateTime.class} - {@link OffsetDateTimeConverter}</li>
550      * <li>{@code OffsetTime.class} - {@link OffsetTimeConverter}</li>
551      * <li>{@code ZonedDateTime.class} - {@link ZonedDateTimeConverter}</li>
552      * <li>{@code Duration.class} - {@link DurationConverter}</li>
553      * <li>{@code MonthDay.class} - {@link MonthDayConverter}</li>
554      * <li>{@code Period.class} - {@link PeriodConverter}</li>
555      * <li>{@code Year.class} - {@link YearConverter}</li>
556      * <li>{@code YearMonth.class} - {@link YearMonthConverter}</li>
557      * <li>{@code ZoneId.class} - {@link ZoneIdConverter}</li>
558      * <li>{@code ZoneOffset.class} - {@link ZoneOffsetConverter}</li>
559      * </ul>
560      *
561      * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code> {@code false} if a
562      *                       default value should be used.
563      */
564     private void registerOther(final boolean throwException) {
565         // @formatter:off
566         register(Class.class,          throwException ? new ClassConverter<>()        : new ClassConverter<>(null));
567         register(Color.class,          throwException ? new ColorConverter()          : new ColorConverter(null));
568         register(Enum.class,           throwException ? new EnumConverter()           : new EnumConverter(null));
569         register(java.util.Date.class, throwException ? new DateConverter()           : new DateConverter(null));
570         register(Dimension.class,      throwException ? new DimensionConverter()      : new DimensionConverter(null));
571         register(Calendar.class,       throwException ? new CalendarConverter()       : new CalendarConverter(null));
572         register(File.class,           throwException ? new FileConverter()           : new FileConverter(null));
573         register(InetAddress.class,    throwException ? new InetAddressConverter()    : new InetAddressConverter(null));
574         register(Path.class,           throwException ? new PathConverter()           : new PathConverter(null));
575         register(java.sql.Date.class,  throwException ? new SqlDateConverter()        : new SqlDateConverter(null));
576         register(java.sql.Time.class,  throwException ? new SqlTimeConverter()        : new SqlTimeConverter(null));
577         register(Timestamp.class,      throwException ? new SqlTimestampConverter()   : new SqlTimestampConverter(null));
578         register(URL.class,            throwException ? new URLConverter()            : new URLConverter(null));
579         register(URI.class,            throwException ? new URIConverter()            : new URIConverter(null));
580         register(UUID.class,           throwException ? new UUIDConverter()           : new UUIDConverter(null));
581         register(LocalDate.class,      throwException ? new LocalDateConverter()      : new LocalDateConverter(null));
582         register(LocalDateTime.class,  throwException ? new LocalDateTimeConverter()  : new LocalDateTimeConverter(null));
583         register(LocalTime.class,      throwException ? new LocalTimeConverter()      : new LocalTimeConverter(null));
584         register(Locale.class,         throwException ? new LocaleConverter()         : new LocaleConverter(null));
585         register(OffsetDateTime.class, throwException ? new OffsetDateTimeConverter() : new OffsetDateTimeConverter(null));
586         register(OffsetTime.class,     throwException ? new OffsetTimeConverter()     : new OffsetTimeConverter(null));
587         register(ZonedDateTime.class,  throwException ? new ZonedDateTimeConverter()  : new ZonedDateTimeConverter(null));
588         register(Duration.class,       throwException ? new DurationConverter()       : new DurationConverter(null));
589         register(MonthDay.class,       throwException ? new MonthDayConverter()       : new MonthDayConverter(null));
590         register(Pattern.class,        throwException ? new PatternConverter()        : new PatternConverter(null));
591         register(Period.class,         throwException ? new PeriodConverter()         : new PeriodConverter(null));
592         register(Point.class,          throwException ? new PointConverter()          : new PointConverter(null));
593         register(Year.class,           throwException ? new YearConverter()           : new YearConverter(null));
594         register(YearMonth.class,      throwException ? new YearMonthConverter()      : new YearMonthConverter(null));
595         register(ZoneId.class,         throwException ? new ZoneIdConverter()         : new ZoneIdConverter(null));
596         register(ZoneOffset.class,     throwException ? new ZoneOffsetConverter()     : new ZoneOffsetConverter(null));
597         // @formatter:on
598     }
599 
600     /**
601      * Registers the converters for primitive types.
602      * </p>
603      * This method registers the following converters:
604      * <ul>
605      * <li>{@code Boolean.TYPE} - {@link BooleanConverter}</li>
606      * <li>{@code Byte.TYPE} - {@link ByteConverter}</li>
607      * <li>{@code Character.TYPE} - {@link CharacterConverter}</li>
608      * <li>{@code Double.TYPE} - {@link DoubleConverter}</li>
609      * <li>{@code Float.TYPE} - {@link FloatConverter}</li>
610      * <li>{@code Integer.TYPE} - {@link IntegerConverter}</li>
611      * <li>{@code Long.TYPE} - {@link LongConverter}</li>
612      * <li>{@code Short.TYPE} - {@link ShortConverter}</li>
613      * </ul>
614      *
615      * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code> {@code false} if a
616      *                       default value should be used.
617      */
618     private void registerPrimitives(final boolean throwException) {
619         register(Boolean.TYPE, throwException ? new BooleanConverter() : new BooleanConverter(Boolean.FALSE));
620         register(Byte.TYPE, throwException ? new ByteConverter() : new ByteConverter(ZERO));
621         register(Character.TYPE, throwException ? new CharacterConverter() : new CharacterConverter(SPACE));
622         register(Double.TYPE, throwException ? new DoubleConverter() : new DoubleConverter(ZERO));
623         register(Float.TYPE, throwException ? new FloatConverter() : new FloatConverter(ZERO));
624         register(Integer.TYPE, throwException ? new IntegerConverter() : new IntegerConverter(ZERO));
625         register(Long.TYPE, throwException ? new LongConverter() : new LongConverter(ZERO));
626         register(Short.TYPE, throwException ? new ShortConverter() : new ShortConverter(ZERO));
627     }
628 
629     /**
630      * Registers the converters for standard types.
631      * </p>
632      * This method registers the following converters:
633      * <ul>
634      * <li>{@code BigDecimal.class} - {@link BigDecimalConverter}</li>
635      * <li>{@code BigInteger.class} - {@link BigIntegerConverter}</li>
636      * <li>{@code Boolean.class} - {@link BooleanConverter}</li>
637      * <li>{@code Byte.class} - {@link ByteConverter}</li>
638      * <li>{@code Character.class} - {@link CharacterConverter}</li>
639      * <li>{@code Double.class} - {@link DoubleConverter}</li>
640      * <li>{@code Float.class} - {@link FloatConverter}</li>
641      * <li>{@code Integer.class} - {@link IntegerConverter}</li>
642      * <li>{@code Long.class} - {@link LongConverter}</li>
643      * <li>{@code Short.class} - {@link ShortConverter}</li>
644      * <li>{@code String.class} - {@link StringConverter}</li>
645      * </ul>
646      *
647      * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code>
648      *                       {@code false} if a default value should be used.
649      * @param defaultNull {@code true}if the <em>standard</em> converters
650      * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)})
651      * should use a default value of {@code null</code>, otherwise <code>false}.
652      * N.B. This values is ignored if {@code throwException</code> is <code>true}
653      */
654     private void registerStandard(final boolean throwException, final boolean defaultNull) {
655 
656         final Number defaultNumber = defaultNull ? null : ZERO;
657         final BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal("0.0");
658         final BigInteger bigIntDeflt = defaultNull ? null : new BigInteger("0");
659         final Boolean booleanDefault = defaultNull ? null : Boolean.FALSE;
660         final Character charDefault = defaultNull ? null : SPACE;
661         final String stringDefault = defaultNull ? null : "";
662 
663         register(BigDecimal.class, throwException ? new BigDecimalConverter() : new BigDecimalConverter(bigDecDeflt));
664         register(BigInteger.class, throwException ? new BigIntegerConverter() : new BigIntegerConverter(bigIntDeflt));
665         register(Boolean.class, throwException ? new BooleanConverter() : new BooleanConverter(booleanDefault));
666         register(Byte.class, throwException ? new ByteConverter() : new ByteConverter(defaultNumber));
667         register(Character.class, throwException ? new CharacterConverter() : new CharacterConverter(charDefault));
668         register(Double.class, throwException ? new DoubleConverter() : new DoubleConverter(defaultNumber));
669         register(Float.class, throwException ? new FloatConverter() : new FloatConverter(defaultNumber));
670         register(Integer.class, throwException ? new IntegerConverter() : new IntegerConverter(defaultNumber));
671         register(Long.class, throwException ? new LongConverter() : new LongConverter(defaultNumber));
672         register(Short.class, throwException ? new ShortConverter() : new ShortConverter(defaultNumber));
673         register(String.class, throwException ? new StringConverter() : new StringConverter(stringDefault));
674 
675     }
676 }