PropertyConverter.java

  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. package org.apache.commons.configuration2.convert;

  18. import java.awt.Color;
  19. import java.io.File;
  20. import java.lang.reflect.Constructor;
  21. import java.lang.reflect.InvocationTargetException;
  22. import java.math.BigDecimal;
  23. import java.math.BigInteger;
  24. import java.net.InetAddress;
  25. import java.net.MalformedURLException;
  26. import java.net.URI;
  27. import java.net.URISyntaxException;
  28. import java.net.URL;
  29. import java.net.UnknownHostException;
  30. import java.nio.file.Path;
  31. import java.nio.file.Paths;
  32. import java.text.ParseException;
  33. import java.text.SimpleDateFormat;
  34. import java.time.Duration;
  35. import java.time.format.DateTimeParseException;
  36. import java.util.Calendar;
  37. import java.util.Date;
  38. import java.util.Locale;
  39. import java.util.Objects;
  40. import java.util.regex.Pattern;
  41. import java.util.regex.PatternSyntaxException;

  42. import org.apache.commons.configuration2.ex.ConversionException;
  43. import org.apache.commons.lang3.BooleanUtils;
  44. import org.apache.commons.lang3.StringUtils;

  45. /**
  46.  * A utility class to convert the configuration properties into any type.
  47.  *
  48.  * @since 2.8.0
  49.  */
  50. public final class PropertyConverter {

  51.     /** Constant for the prefix of hex numbers. */
  52.     private static final String HEX_PREFIX = "0x";

  53.     /** Constant for the radix of hex numbers. */
  54.     private static final int HEX_RADIX = 16;

  55.     /** Constant for the prefix of binary numbers. */
  56.     private static final String BIN_PREFIX = "0b";

  57.     /** Constant for the radix of binary numbers. */
  58.     private static final int BIN_RADIX = 2;

  59.     /** Constant for the argument classes of the Number constructor that takes a String. */
  60.     private static final Class<?>[] CONSTR_ARGS = {String.class};

  61.     /** The fully qualified name of {@code javax.mail.internet.InternetAddress}, as used in the javamail-1.* API.  */
  62.     private static final String INTERNET_ADDRESS_CLASSNAME_JAVAX = "javax.mail.internet.InternetAddress";

  63.     /** The fully qualified name of {@code jakarta.mail.internet.InternetAddress}, as used in the javamail-2.0+ API. */
  64.     private static final String INTERNET_ADDRESS_CLASSNAME_JAKARTA = "jakarta.mail.internet.InternetAddress";

  65.     /**
  66.      * Converts a value to a constant of an enumeration class.
  67.      *
  68.      * @param enumClass the enumeration class
  69.      * @param value the value to be converted
  70.      * @return the converted value
  71.      */
  72.     @SuppressWarnings("unchecked")
  73.     // conversion is safe because we know that the class is an Enum class
  74.     private static Object convertToEnum(final Class<?> enumClass, final Object value) {
  75.         return toEnum(value, enumClass.asSubclass(Enum.class));
  76.     }

  77.     /**
  78.      * Converts the specified value object to the given target data class. If additional
  79.      * information is required for this conversion, it is obtained from the passed in {@code DefaultConversionHandler}
  80.      * object. If the class is a primitive type (Integer.TYPE, Boolean.TYPE, etc), the value returned will use the wrapper
  81.      * type (Integer.class, Boolean.class, etc).
  82.      *
  83.      * @param cls the target class of the converted value
  84.      * @param value the value to convert
  85.      * @param convHandler the conversion handler object
  86.      * @return the converted value
  87.      * @throws ConversionException if the value is not compatible with the requested type
  88.      */
  89.     public static Object to(final Class<?> cls, final Object value, final DefaultConversionHandler convHandler) throws ConversionException {
  90.         if (cls.isInstance(value)) {
  91.             return value; // no conversion needed
  92.         }

  93.         if (String.class.equals(cls)) {
  94.             return String.valueOf(value);
  95.         }
  96.         if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) {
  97.             return toBoolean(value);
  98.         }
  99.         if (Character.class.equals(cls) || Character.TYPE.equals(cls)) {
  100.             return toCharacter(value);
  101.         }
  102.         if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) {
  103.             if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) {
  104.                 return toInteger(value);
  105.             }
  106.             if (Long.class.equals(cls) || Long.TYPE.equals(cls)) {
  107.                 return toLong(value);
  108.             }
  109.             if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) {
  110.                 return toByte(value);
  111.             }
  112.             if (Short.class.equals(cls) || Short.TYPE.equals(cls)) {
  113.                 return toShort(value);
  114.             }
  115.             if (Float.class.equals(cls) || Float.TYPE.equals(cls)) {
  116.                 return toFloat(value);
  117.             }
  118.             if (Double.class.equals(cls) || Double.TYPE.equals(cls)) {
  119.                 return toDouble(value);
  120.             }
  121.             if (BigInteger.class.equals(cls)) {
  122.                 return toBigInteger(value);
  123.             }
  124.             if (BigDecimal.class.equals(cls)) {
  125.                 return toBigDecimal(value);
  126.             }
  127.             return toNumber(value, cls);
  128.         }
  129.         if (Date.class.equals(cls)) {
  130.             return toDate(value, convHandler.getDateFormat());
  131.         }
  132.         if (Calendar.class.equals(cls)) {
  133.             return toCalendar(value, convHandler.getDateFormat());
  134.         }
  135.         if (File.class.equals(cls)) {
  136.             return toFile(value);
  137.         }
  138.         if (Path.class.equals(cls)) {
  139.             return toPath(value);
  140.         }
  141.         if (URI.class.equals(cls)) {
  142.             return toURI(value);
  143.         }
  144.         if (URL.class.equals(cls)) {
  145.             return toURL(value);
  146.         }
  147.         if (Pattern.class.equals(cls)) {
  148.             return toPattern(value);
  149.         }
  150.         if (Locale.class.equals(cls)) {
  151.             return toLocale(value);
  152.         }
  153.         if (cls.isEnum()) {
  154.             return convertToEnum(cls, value);
  155.         }
  156.         if (Color.class.equals(cls)) {
  157.             return toColor(value);
  158.         }
  159.         if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAVAX)) {
  160.             // javamail-1.* With javax.mail.* namespace.
  161.             return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAVAX);
  162.         }
  163.         if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAKARTA)) {
  164.             // javamail-2.0+, with jakarta.mail.* namespace.
  165.             return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAKARTA);
  166.         }
  167.         if (InetAddress.class.isAssignableFrom(cls)) {
  168.             return toInetAddress(value);
  169.         }
  170.         if (Duration.class.equals(cls)) {
  171.             return toDuration(value);
  172.         }

  173.         throw new ConversionException("The value '" + value + "' (" + value.getClass() + ")" + " can't be converted to a " + cls.getName() + " object");
  174.     }

  175.     /**
  176.      * Converts the specified object into a BigDecimal.
  177.      *
  178.      * @param value the value to convert
  179.      * @return the converted value
  180.      * @throws ConversionException thrown if the value cannot be converted to a BigDecimal
  181.      */
  182.     public static BigDecimal toBigDecimal(final Object value) throws ConversionException {
  183.         final Number n = toNumber(value, BigDecimal.class);
  184.         if (n instanceof BigDecimal) {
  185.             return (BigDecimal) n;
  186.         }
  187.         return BigDecimal.valueOf(n.doubleValue());
  188.     }

  189.     /**
  190.      * Converts the specified object into a BigInteger.
  191.      *
  192.      * @param value the value to convert
  193.      * @return the converted value
  194.      * @throws ConversionException thrown if the value cannot be converted to a BigInteger
  195.      */
  196.     public static BigInteger toBigInteger(final Object value) throws ConversionException {
  197.         final Number n = toNumber(value, BigInteger.class);
  198.         if (n instanceof BigInteger) {
  199.             return (BigInteger) n;
  200.         }
  201.         return BigInteger.valueOf(n.longValue());
  202.     }

  203.     /**
  204.      * Converts the specified object into a Boolean. Internally the {@code org.apache.commons.lang.BooleanUtils} class from
  205.      * the <a href="https://commons.apache.org/lang/">Commons Lang</a> project is used to perform this conversion. This
  206.      * class accepts some more tokens for the boolean value of <strong>true</strong>, for example {@code yes} and {@code on}. Please refer to
  207.      * the documentation of this class for more details.
  208.      *
  209.      * @param value the value to convert
  210.      * @return the converted value
  211.      * @throws ConversionException thrown if the value cannot be converted to a boolean
  212.      */
  213.     public static Boolean toBoolean(final Object value) throws ConversionException {
  214.         if (value instanceof Boolean) {
  215.             return (Boolean) value;
  216.         }
  217.         if (!(value instanceof String)) {
  218.             throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
  219.         }
  220.         final Boolean b = BooleanUtils.toBooleanObject((String) value);
  221.         if (b == null) {
  222.             throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
  223.         }
  224.         return b;
  225.     }

  226.     /**
  227.      * Converts the specified object into a Byte.
  228.      *
  229.      * @param value the value to convert
  230.      * @return the converted value
  231.      * @throws ConversionException thrown if the value cannot be converted to a byte
  232.      */
  233.     public static Byte toByte(final Object value) throws ConversionException {
  234.         final Number n = toNumber(value, Byte.class);
  235.         if (n instanceof Byte) {
  236.             return (Byte) n;
  237.         }
  238.         return n.byteValue();
  239.     }

  240.     /**
  241.      * Converts the specified object into a Calendar.
  242.      *
  243.      * @param value the value to convert
  244.      * @param format the DateFormat pattern to parse String values
  245.      * @return the converted value
  246.      * @throws ConversionException thrown if the value cannot be converted to a Calendar
  247.      */
  248.     public static Calendar toCalendar(final Object value, final String format) throws ConversionException {
  249.         if (value instanceof Calendar) {
  250.             return (Calendar) value;
  251.         }
  252.         if (value instanceof Date) {
  253.             final Calendar calendar = Calendar.getInstance();
  254.             calendar.setTime((Date) value);
  255.             return calendar;
  256.         }
  257.         if (!(value instanceof String)) {
  258.             throw new ConversionException("The value " + value + " can't be converted to a Calendar");
  259.         }
  260.         try {
  261.             final Calendar calendar = Calendar.getInstance();
  262.             calendar.setTime(new SimpleDateFormat(format).parse((String) value));
  263.             return calendar;
  264.         } catch (final ParseException e) {
  265.             throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);
  266.         }
  267.     }

  268.     /**
  269.      * Converts the specified value object to a {@code Character}. This method converts the passed in object to a string. If
  270.      * the string has exactly one character, this character is returned as result. Otherwise, conversion fails.
  271.      *
  272.      * @param value the value to be converted
  273.      * @return the resulting {@code Character} object
  274.      * @throws ConversionException if the conversion is not possible
  275.      */
  276.     public static Character toCharacter(final Object value) throws ConversionException {
  277.         final String strValue = String.valueOf(value);
  278.         if (strValue.length() == 1) {
  279.             return Character.valueOf(strValue.charAt(0));
  280.         }
  281.         throw new ConversionException(String.format("The value '%s' cannot be converted to a Character object!", strValue));
  282.     }

  283.     /**
  284.      * Converts the specified object into a Color. If the value is a String, the format allowed is
  285.      * (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples:
  286.      * <ul>
  287.      * <li>FF0000 (red)</li>
  288.      * <li>0000FFA0 (semi transparent blue)</li>
  289.      * <li>#CCCCCC (gray)</li>
  290.      * <li>#00FF00A0 (semi transparent green)</li>
  291.      * </ul>
  292.      *
  293.      * @param value the value to convert
  294.      * @return the converted value
  295.      * @throws ConversionException thrown if the value cannot be converted to a Color
  296.      */
  297.     public static Color toColor(final Object value) throws ConversionException {
  298.         if (value instanceof Color) {
  299.             return (Color) value;
  300.         }
  301.         if (!(value instanceof String) || StringUtils.isBlank((String) value)) {
  302.             throw new ConversionException("The value " + value + " can't be converted to a Color");
  303.         }
  304.         String color = ((String) value).trim();

  305.         final int[] components = new int[3];

  306.         // check the size of the string
  307.         final int minlength = components.length * 2;
  308.         if (color.length() < minlength) {
  309.             throw new ConversionException("The value " + value + " can't be converted to a Color");
  310.         }

  311.         // remove the leading #
  312.         if (color.startsWith("#")) {
  313.             color = color.substring(1);
  314.         }

  315.         try {
  316.             // parse the components
  317.             for (int i = 0; i < components.length; i++) {
  318.                 components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);
  319.             }

  320.             // parse the transparency
  321.             final int alpha;
  322.             if (color.length() >= minlength + 2) {
  323.                 alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);
  324.             } else {
  325.                 alpha = Color.black.getAlpha();
  326.             }

  327.             return new Color(components[0], components[1], components[2], alpha);
  328.         } catch (final Exception e) {
  329.             throw new ConversionException("The value " + value + " can't be converted to a Color", e);
  330.         }
  331.     }

  332.     /**
  333.      * Converts the specified object into a Date.
  334.      *
  335.      * @param value the value to convert
  336.      * @param format the DateFormat pattern to parse String values
  337.      * @return the converted value
  338.      * @throws ConversionException thrown if the value cannot be converted to a Calendar
  339.      */
  340.     public static Date toDate(final Object value, final String format) throws ConversionException {
  341.         if (value instanceof Date) {
  342.             return (Date) value;
  343.         }
  344.         if (value instanceof Calendar) {
  345.             return ((Calendar) value).getTime();
  346.         }
  347.         if (!(value instanceof String)) {
  348.             throw new ConversionException("The value " + value + " can't be converted to a Date");
  349.         }
  350.         try {
  351.             return new SimpleDateFormat(format).parse((String) value);
  352.         } catch (final ParseException e) {
  353.             throw new ConversionException("The value " + value + " can't be converted to a Date", e);
  354.         }
  355.     }

  356.     /**
  357.      * Converts the specified object into a Double.
  358.      *
  359.      * @param value the value to convert
  360.      * @return the converted value
  361.      * @throws ConversionException thrown if the value cannot be converted to a Double
  362.      */
  363.     public static Double toDouble(final Object value) throws ConversionException {
  364.         final Number n = toNumber(value, Double.class);
  365.         if (n instanceof Double) {
  366.             return (Double) n;
  367.         }
  368.         return Double.valueOf(n.doubleValue());
  369.     }

  370.     /**
  371.      * Converts the specified object into a Duration.
  372.      *
  373.      * @param value the value to convert
  374.      * @return the converted value
  375.      * @throws ConversionException thrown if the value cannot be converted to a Duration
  376.      * @since 2.8.0
  377.      */
  378.     public static Duration toDuration(final Object value) throws ConversionException {
  379.         if (value instanceof Duration) {
  380.             return (Duration) value;
  381.         }
  382.         if (value instanceof CharSequence) {
  383.             try {
  384.                 return Duration.parse((CharSequence) value);
  385.             } catch (final DateTimeParseException e) {
  386.                 throw new ConversionException("Could not convert " + value + " to Duration", e);
  387.             }
  388.         }
  389.         throw new ConversionException("The value " + value + " can't be converted to a Duration");
  390.     }

  391.     /**
  392.      * Converts the specified value into an {@link Enum}.
  393.      *
  394.      * @param value the value to convert
  395.      * @param cls the type of the enumeration
  396.      * @return the converted value
  397.      * @throws ConversionException thrown if the value cannot be converted to an enumeration
  398.      * @since 1.5
  399.      */
  400.     static <E extends Enum<E>> E toEnum(final Object value, final Class<E> cls) throws ConversionException {
  401.         if (value.getClass().equals(cls)) {
  402.             return cls.cast(value);
  403.         }
  404.         if (value instanceof String) {
  405.             try {
  406.                 return Enum.valueOf(cls, (String) value);
  407.             } catch (final Exception e) {
  408.                 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
  409.             }
  410.         }
  411.         if (!(value instanceof Number)) {
  412.             throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
  413.         }
  414.         try {
  415.             final E[] enumConstants = cls.getEnumConstants();
  416.             return enumConstants[((Number) value).intValue()];
  417.         } catch (final Exception e) {
  418.             throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
  419.         }
  420.     }

  421.     /**
  422.      * Converts the specified object into a File.
  423.      *
  424.      * @param value the value to convert
  425.      * @return the converted value
  426.      * @throws ConversionException thrown if the value cannot be converted to a File
  427.      * @since 2.3
  428.      */
  429.     public static File toFile(final Object value) throws ConversionException {
  430.         if (value instanceof File) {
  431.             return (File) value;
  432.         }
  433.         if (value instanceof Path) {
  434.             return ((Path) value).toFile();
  435.         }
  436.         if (value instanceof String) {
  437.             return new File((String) value);
  438.         }
  439.         throw new ConversionException("The value " + value + " can't be converted to a File");
  440.     }

  441.     /**
  442.      * Converts the specified object into a Float.
  443.      *
  444.      * @param value the value to convert
  445.      * @return the converted value
  446.      * @throws ConversionException thrown if the value cannot be converted to a Float
  447.      */
  448.     public static Float toFloat(final Object value) throws ConversionException {
  449.         final Number n = toNumber(value, Float.class);
  450.         if (n instanceof Float) {
  451.             return (Float) n;
  452.         }
  453.         return Float.valueOf(n.floatValue());
  454.     }

  455.     /**
  456.      * Converts the specified value into an internet address.
  457.      *
  458.      * @param value the value to convert
  459.      * @return the converted value
  460.      * @throws ConversionException thrown if the value cannot be converted to a InetAddress
  461.      * @since 1.5
  462.      */
  463.     static InetAddress toInetAddress(final Object value) throws ConversionException {
  464.         if (value instanceof InetAddress) {
  465.             return (InetAddress) value;
  466.         }
  467.         if (!(value instanceof String)) {
  468.             throw new ConversionException("The value " + value + " can't be converted to a InetAddress");
  469.         }
  470.         try {
  471.             return InetAddress.getByName((String) value);
  472.         } catch (final UnknownHostException e) {
  473.             throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e);
  474.         }
  475.     }

  476.     /**
  477.      * Converts the specified object into an Integer.
  478.      *
  479.      * @param value the value to convert
  480.      * @return the converted value
  481.      * @throws ConversionException thrown if the value cannot be converted to an integer
  482.      */
  483.     public static Integer toInteger(final Object value) throws ConversionException {
  484.         final Number n = toNumber(value, Integer.class);
  485.         if (n instanceof Integer) {
  486.             return (Integer) n;
  487.         }
  488.         return n.intValue();
  489.     }

  490.     /**
  491.      * Converts the specified value into an email address with the given class name.
  492.      *
  493.      * @param value the value to convert
  494.      * @param targetClassName the fully qualified name of the {@code InternetAddress} class to convert to, for example,
  495.      *      {@value #INTERNET_ADDRESS_CLASSNAME_JAVAX} or {@value #INTERNET_ADDRESS_CLASSNAME_JAKARTA}
  496.      * @return the converted value
  497.      * @throws ConversionException thrown if the value cannot be converted to an email address
  498.      * @since 1.5
  499.      */
  500.     static Object toInternetAddress(final Object value, final String targetClassName) throws ConversionException {
  501.         if (value.getClass().getName().equals(targetClassName)) {
  502.             return value;
  503.         }
  504.         if (!(value instanceof String)) {
  505.             throw new ConversionException("The value " + value + " can't be converted to an InternetAddress");
  506.         }
  507.         try {
  508.             final Constructor<?> ctor = Class.forName(targetClassName).getConstructor(String.class);
  509.             return ctor.newInstance(value);
  510.         } catch (final Exception e) {
  511.             throw new ConversionException("The value " + value + " can't be converted to an InternetAddress", e);
  512.         }
  513.     }

  514.     /**
  515.      * Converts the specified object into a Locale.
  516.      *
  517.      * @param value the value to convert
  518.      * @return the converted value
  519.      * @throws ConversionException thrown if the value cannot be converted to a Locale
  520.      */
  521.     public static Locale toLocale(final Object value) throws ConversionException {
  522.         if (value instanceof Locale) {
  523.             return (Locale) value;
  524.         }
  525.         if (!(value instanceof String)) {
  526.             throw new ConversionException("The value " + value + " can't be converted to a Locale");
  527.         }
  528.         final String[] elements = ((String) value).split("_");
  529.         final int size = elements.length;

  530.         if (size >= 1 && (elements[0].length() == 2 || elements[0].isEmpty())) {
  531.             final String language = elements[0];
  532.             final String country = size >= 2 ? elements[1] : "";
  533.             final String variant = size >= 3 ? elements[2] : "";

  534.             return new Locale(language, country, variant);
  535.         }
  536.         throw new ConversionException("The value " + value + " can't be converted to a Locale");
  537.     }

  538.     /**
  539.      * Converts the specified object into a Long.
  540.      *
  541.      * @param value the value to convert
  542.      * @return the converted value
  543.      * @throws ConversionException thrown if the value cannot be converted to a Long
  544.      */
  545.     public static Long toLong(final Object value) throws ConversionException {
  546.         final Number n = toNumber(value, Long.class);
  547.         if (n instanceof Long) {
  548.             return (Long) n;
  549.         }
  550.         return n.longValue();
  551.     }

  552.     /**
  553.      * Tries to convert the specified object into a number object. This method is used by the conversion methods for number
  554.      * types. Note that the return value is not in always of the specified target class, but only if a new object has to be
  555.      * created.
  556.      *
  557.      * @param value the value to be converted (must not be <strong>null</strong>)
  558.      * @param targetClass the target class of the conversion (must be derived from {@link Number})
  559.      * @return the converted number
  560.      * @throws ConversionException if the object cannot be converted
  561.      */
  562.     static Number toNumber(final Object value, final Class<?> targetClass) throws ConversionException {
  563.         if (value instanceof Number) {
  564.             return (Number) value;
  565.         }
  566.         final String str = Objects.toString(value, null);
  567.         if (StringUtils.startsWithAny(str, HEX_PREFIX)) {
  568.             try {
  569.                 return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX);
  570.             } catch (final NumberFormatException nex) {
  571.                 throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid hex number.", nex);
  572.             }
  573.         }

  574.         if (StringUtils.startsWithAny(str, BIN_PREFIX)) {
  575.             try {
  576.                 return new BigInteger(str.substring(BIN_PREFIX.length()), BIN_RADIX);
  577.             } catch (final NumberFormatException nex) {
  578.                 throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid binary number.", nex);
  579.             }
  580.         }

  581.         try {
  582.             final Constructor<?> constr = targetClass.getConstructor(CONSTR_ARGS);
  583.             return (Number) constr.newInstance(str);
  584.         } catch (final InvocationTargetException itex) {
  585.             throw new ConversionException("Could not convert " + str + " to " + targetClass.getName(), itex.getTargetException());
  586.         } catch (final Exception ex) {
  587.             // Treat all possible exceptions the same way
  588.             throw new ConversionException("Conversion error when trying to convert " + str + " to " + targetClass.getName(), ex);
  589.         }
  590.     }

  591.     /**
  592.      * Converts the specified object into a Path.
  593.      *
  594.      * @param value the value to convert
  595.      * @return the converted value
  596.      * @throws ConversionException thrown if the value cannot be converted to a Path
  597.      * @since 2.3
  598.      */
  599.     public static Path toPath(final Object value) throws ConversionException {
  600.         if (value instanceof File) {
  601.             return ((File) value).toPath();
  602.         }
  603.         if (value instanceof Path) {
  604.             return (Path) value;
  605.         }
  606.         if (value instanceof String) {
  607.             return Paths.get((String) value);
  608.         }
  609.         throw new ConversionException("The value " + value + " can't be converted to a Path");
  610.     }

  611.     /**
  612.      * Converts the specified object into a Pattern.
  613.      *
  614.      * @param value the value to convert
  615.      * @return the converted value
  616.      * @throws ConversionException thrown if the value cannot be converted to a Pattern
  617.      */
  618.     public static Pattern toPattern(final Object value) throws ConversionException {
  619.         if (value instanceof Pattern) {
  620.             return (Pattern) value;
  621.         }
  622.         if (!(value instanceof String)) {
  623.             throw new ConversionException("The value " + value + " can't be converted to a Pattern");
  624.         }
  625.         try {
  626.             return Pattern.compile((String) value);
  627.         } catch (final PatternSyntaxException e) {
  628.             throw new ConversionException("The value " + value + " can't be converted to a Pattern", e);
  629.         }
  630.     }

  631.     /**
  632.      * Converts the specified object into a Short.
  633.      *
  634.      * @param value the value to convert
  635.      * @return the converted value
  636.      * @throws ConversionException thrown if the value cannot be converted to a short
  637.      */
  638.     public static Short toShort(final Object value) throws ConversionException {
  639.         final Number n = toNumber(value, Short.class);
  640.         if (n instanceof Short) {
  641.             return (Short) n;
  642.         }
  643.         return n.shortValue();
  644.     }

  645.     /**
  646.      * Converts the specified object into an URI.
  647.      *
  648.      * @param value the value to convert
  649.      * @return the converted value
  650.      * @throws ConversionException thrown if the value cannot be converted to an URI
  651.      */
  652.     public static URI toURI(final Object value) throws ConversionException {
  653.         if (value instanceof URI) {
  654.             return (URI) value;
  655.         }
  656.         if (!(value instanceof String)) {
  657.             throw new ConversionException("The value " + value + " can't be converted to an URI");
  658.         }
  659.         try {
  660.             return new URI((String) value);
  661.         } catch (final URISyntaxException e) {
  662.             throw new ConversionException("The value " + value + " can't be converted to an URI", e);
  663.         }
  664.     }

  665.     /**
  666.      * Converts the specified object into an URL.
  667.      *
  668.      * @param value the value to convert
  669.      * @return the converted value
  670.      * @throws ConversionException thrown if the value cannot be converted to an URL
  671.      */
  672.     public static URL toURL(final Object value) throws ConversionException {
  673.         if (value instanceof URL) {
  674.             return (URL) value;
  675.         }
  676.         if (!(value instanceof String)) {
  677.             throw new ConversionException("The value " + value + " can't be converted to an URL");
  678.         }
  679.         try {
  680.             return new URL((String) value);
  681.         } catch (final MalformedURLException e) {
  682.             throw new ConversionException("The value " + value + " can't be converted to an URL", e);
  683.         }
  684.     }

  685.     /**
  686.      * Private constructor prevents instances from being created.
  687.      */
  688.     private PropertyConverter() {
  689.         // presvents instantiation.
  690.     }
  691. }