001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.configuration2.convert; 019 020import java.awt.Color; 021import java.io.File; 022import java.lang.reflect.Constructor; 023import java.lang.reflect.InvocationTargetException; 024import java.math.BigDecimal; 025import java.math.BigInteger; 026import java.net.InetAddress; 027import java.net.MalformedURLException; 028import java.net.URI; 029import java.net.URISyntaxException; 030import java.net.URL; 031import java.net.UnknownHostException; 032import java.nio.file.Path; 033import java.nio.file.Paths; 034import java.text.ParseException; 035import java.text.SimpleDateFormat; 036import java.time.Duration; 037import java.time.format.DateTimeParseException; 038import java.util.Calendar; 039import java.util.Date; 040import java.util.Locale; 041import java.util.Objects; 042import java.util.regex.Pattern; 043import java.util.regex.PatternSyntaxException; 044 045import org.apache.commons.configuration2.ex.ConversionException; 046import org.apache.commons.lang3.BooleanUtils; 047import org.apache.commons.lang3.StringUtils; 048import org.apache.commons.lang3.Strings; 049 050/** 051 * A utility class to convert the configuration properties into any type. 052 * 053 * @since 2.8.0 054 */ 055public final class PropertyConverter { 056 057 /** Constant for the prefix of hex numbers. */ 058 private static final String HEX_PREFIX = "0x"; 059 060 /** Constant for the radix of hex numbers. */ 061 private static final int HEX_RADIX = 16; 062 063 /** Constant for the prefix of binary numbers. */ 064 private static final String BIN_PREFIX = "0b"; 065 066 /** Constant for the radix of binary numbers. */ 067 private static final int BIN_RADIX = 2; 068 069 /** Constant for the argument classes of the Number constructor that takes a String. */ 070 private static final Class<?>[] CONSTR_ARGS = {String.class}; 071 072 /** The fully qualified name of {@code javax.mail.internet.InternetAddress}, as used in the javamail-1.* API. */ 073 private static final String INTERNET_ADDRESS_CLASSNAME_JAVAX = "javax.mail.internet.InternetAddress"; 074 075 /** The fully qualified name of {@code jakarta.mail.internet.InternetAddress}, as used in the javamail-2.0+ API. */ 076 private static final String INTERNET_ADDRESS_CLASSNAME_JAKARTA = "jakarta.mail.internet.InternetAddress"; 077 078 /** 079 * Converts a value to a constant of an enumeration class. 080 * 081 * @param enumClass the enumeration class 082 * @param value the value to be converted 083 * @return the converted value 084 */ 085 @SuppressWarnings("unchecked") 086 // conversion is safe because we know that the class is an Enum class 087 private static Object convertToEnum(final Class<?> enumClass, final Object value) { 088 return toEnum(value, enumClass.asSubclass(Enum.class)); 089 } 090 091 /** 092 * Converts the specified value object to the given target data class. If additional 093 * information is required for this conversion, it is obtained from the passed in {@code DefaultConversionHandler} 094 * object. If the class is a primitive type (Integer.TYPE, Boolean.TYPE, etc), the value returned will use the wrapper 095 * type (Integer.class, Boolean.class, etc). 096 * 097 * @param cls the target class of the converted value 098 * @param value the value to convert 099 * @param convHandler the conversion handler object 100 * @return the converted value 101 * @throws ConversionException if the value is not compatible with the requested type 102 */ 103 public static Object to(final Class<?> cls, final Object value, final DefaultConversionHandler convHandler) throws ConversionException { 104 if (cls.isInstance(value)) { 105 return value; // no conversion needed 106 } 107 108 if (String.class.equals(cls)) { 109 return String.valueOf(value); 110 } 111 if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) { 112 return toBoolean(value); 113 } 114 if (Character.class.equals(cls) || Character.TYPE.equals(cls)) { 115 return toCharacter(value); 116 } 117 if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) { 118 if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) { 119 return toInteger(value); 120 } 121 if (Long.class.equals(cls) || Long.TYPE.equals(cls)) { 122 return toLong(value); 123 } 124 if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) { 125 return toByte(value); 126 } 127 if (Short.class.equals(cls) || Short.TYPE.equals(cls)) { 128 return toShort(value); 129 } 130 if (Float.class.equals(cls) || Float.TYPE.equals(cls)) { 131 return toFloat(value); 132 } 133 if (Double.class.equals(cls) || Double.TYPE.equals(cls)) { 134 return toDouble(value); 135 } 136 if (BigInteger.class.equals(cls)) { 137 return toBigInteger(value); 138 } 139 if (BigDecimal.class.equals(cls)) { 140 return toBigDecimal(value); 141 } 142 return toNumber(value, cls); 143 } 144 if (Date.class.equals(cls)) { 145 return toDate(value, convHandler.getDateFormat()); 146 } 147 if (Calendar.class.equals(cls)) { 148 return toCalendar(value, convHandler.getDateFormat()); 149 } 150 if (File.class.equals(cls)) { 151 return toFile(value); 152 } 153 if (Path.class.equals(cls)) { 154 return toPath(value); 155 } 156 if (URI.class.equals(cls)) { 157 return toURI(value); 158 } 159 if (URL.class.equals(cls)) { 160 return toURL(value); 161 } 162 if (Pattern.class.equals(cls)) { 163 return toPattern(value); 164 } 165 if (Locale.class.equals(cls)) { 166 return toLocale(value); 167 } 168 if (cls.isEnum()) { 169 return convertToEnum(cls, value); 170 } 171 if (Color.class.equals(cls)) { 172 return toColor(value); 173 } 174 if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAVAX)) { 175 // javamail-1.* With javax.mail.* namespace. 176 return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAVAX); 177 } 178 if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAKARTA)) { 179 // javamail-2.0+, with jakarta.mail.* namespace. 180 return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAKARTA); 181 } 182 if (InetAddress.class.isAssignableFrom(cls)) { 183 return toInetAddress(value); 184 } 185 if (Duration.class.equals(cls)) { 186 return toDuration(value); 187 } 188 throw new ConversionException("The value '%s' (%s) can't be converted to a %s object", value, value.getClass(), cls.getName()); 189 } 190 191 /** 192 * Converts the specified object into a BigDecimal. 193 * 194 * @param value the value to convert 195 * @return the converted value 196 * @throws ConversionException thrown if the value cannot be converted to a BigDecimal 197 */ 198 public static BigDecimal toBigDecimal(final Object value) throws ConversionException { 199 final Number n = toNumber(value, BigDecimal.class); 200 if (n instanceof BigDecimal) { 201 return (BigDecimal) n; 202 } 203 return BigDecimal.valueOf(n.doubleValue()); 204 } 205 206 /** 207 * Converts the specified object into a BigInteger. 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 BigInteger 212 */ 213 public static BigInteger toBigInteger(final Object value) throws ConversionException { 214 final Number n = toNumber(value, BigInteger.class); 215 if (n instanceof BigInteger) { 216 return (BigInteger) n; 217 } 218 return BigInteger.valueOf(n.longValue()); 219 } 220 221 /** 222 * Converts the specified object into a Boolean. Internally the {@code org.apache.commons.lang.BooleanUtils} class from 223 * the <a href="https://commons.apache.org/lang/">Commons Lang</a> project is used to perform this conversion. This 224 * class accepts some more tokens for the boolean value of <strong>true</strong>, for example {@code yes} and {@code on}. Please refer to 225 * the documentation of this class for more details. 226 * 227 * @param value the value to convert 228 * @return the converted value 229 * @throws ConversionException thrown if the value cannot be converted to a boolean 230 */ 231 public static Boolean toBoolean(final Object value) throws ConversionException { 232 if (value instanceof Boolean) { 233 return (Boolean) value; 234 } 235 if (!(value instanceof String)) { 236 throw new ConversionException("The value %s can't be converted to a Boolean object", value); 237 } 238 final Boolean b = BooleanUtils.toBooleanObject((String) value); 239 if (b == null) { 240 throw new ConversionException("The value %s can't be converted to a Boolean object", value); 241 } 242 return b; 243 } 244 245 /** 246 * Converts the specified object into a Byte. 247 * 248 * @param value the value to convert 249 * @return the converted value 250 * @throws ConversionException thrown if the value cannot be converted to a byte 251 */ 252 public static Byte toByte(final Object value) throws ConversionException { 253 final Number n = toNumber(value, Byte.class); 254 if (n instanceof Byte) { 255 return (Byte) n; 256 } 257 return n.byteValue(); 258 } 259 260 /** 261 * Converts the specified object into a Calendar. 262 * 263 * @param value the value to convert 264 * @param format the DateFormat pattern to parse String values 265 * @return the converted value 266 * @throws ConversionException thrown if the value cannot be converted to a Calendar 267 */ 268 public static Calendar toCalendar(final Object value, final String format) throws ConversionException { 269 if (value instanceof Calendar) { 270 return (Calendar) value; 271 } 272 if (value instanceof Date) { 273 final Calendar calendar = Calendar.getInstance(); 274 calendar.setTime((Date) value); 275 return calendar; 276 } 277 if (!(value instanceof String)) { 278 throw new ConversionException("The value %s can't be converted to a Calendar", value); 279 } 280 try { 281 final Calendar calendar = Calendar.getInstance(); 282 calendar.setTime(new SimpleDateFormat(format).parse((String) value)); 283 return calendar; 284 } catch (final ParseException e) { 285 throw new ConversionException(e, "The value %s can't be converted to a Calendar", value); 286 } 287 } 288 289 /** 290 * Converts the specified value object to a {@code Character}. This method converts the passed in object to a string. If 291 * the string has exactly one character, this character is returned as result. Otherwise, conversion fails. 292 * 293 * @param value the value to be converted 294 * @return the resulting {@code Character} object 295 * @throws ConversionException if the conversion is not possible 296 */ 297 public static Character toCharacter(final Object value) throws ConversionException { 298 final String strValue = String.valueOf(value); 299 if (strValue.length() == 1) { 300 return Character.valueOf(strValue.charAt(0)); 301 } 302 throw new ConversionException("The value '%s' cannot be converted to a Character object!", strValue); 303 } 304 305 /** 306 * Converts the specified object into a Color. If the value is a String, the format allowed is 307 * (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples: 308 * <ul> 309 * <li>FF0000 (red)</li> 310 * <li>0000FFA0 (semi transparent blue)</li> 311 * <li>#CCCCCC (gray)</li> 312 * <li>#00FF00A0 (semi transparent green)</li> 313 * </ul> 314 * 315 * @param value the value to convert 316 * @return the converted value 317 * @throws ConversionException thrown if the value cannot be converted to a Color 318 */ 319 public static Color toColor(final Object value) throws ConversionException { 320 if (value instanceof Color) { 321 return (Color) value; 322 } 323 if (!(value instanceof String) || StringUtils.isBlank((String) value)) { 324 throw new ConversionException("The value %s can't be converted to a Color", value); 325 } 326 String color = ((String) value).trim(); 327 328 final int[] components = new int[3]; 329 330 // check the size of the string 331 final int minlength = components.length * 2; 332 if (color.length() < minlength) { 333 throw new ConversionException("The value %s can't be converted to a Color", value); 334 } 335 336 // remove the leading # 337 if (color.startsWith("#")) { 338 color = color.substring(1); 339 } 340 341 try { 342 // parse the components 343 for (int i = 0; i < components.length; i++) { 344 components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX); 345 } 346 347 // parse the transparency 348 final int alpha; 349 if (color.length() >= minlength + 2) { 350 alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX); 351 } else { 352 alpha = Color.black.getAlpha(); 353 } 354 355 return new Color(components[0], components[1], components[2], alpha); 356 } catch (final Exception e) { 357 throw new ConversionException(e, "The value %s can't be converted to a Color", value); 358 } 359 } 360 361 /** 362 * Converts the specified object into a Date. 363 * 364 * @param value the value to convert 365 * @param format the DateFormat pattern to parse String values 366 * @return the converted value 367 * @throws ConversionException thrown if the value cannot be converted to a Calendar 368 */ 369 public static Date toDate(final Object value, final String format) throws ConversionException { 370 if (value instanceof Date) { 371 return (Date) value; 372 } 373 if (value instanceof Calendar) { 374 return ((Calendar) value).getTime(); 375 } 376 if (!(value instanceof String)) { 377 throw new ConversionException("The value %s can't be converted to a Date", value); 378 } 379 try { 380 return new SimpleDateFormat(format).parse((String) value); 381 } catch (final ParseException e) { 382 throw new ConversionException(e, "The value %s can't be converted to a Date", value); 383 } 384 } 385 386 /** 387 * Converts the specified object into a Double. 388 * 389 * @param value the value to convert 390 * @return the converted value 391 * @throws ConversionException thrown if the value cannot be converted to a Double 392 */ 393 public static Double toDouble(final Object value) throws ConversionException { 394 final Number n = toNumber(value, Double.class); 395 if (n instanceof Double) { 396 return (Double) n; 397 } 398 return Double.valueOf(n.doubleValue()); 399 } 400 401 /** 402 * Converts the specified object into a Duration. 403 * 404 * @param value the value to convert 405 * @return the converted value 406 * @throws ConversionException thrown if the value cannot be converted to a Duration 407 * @since 2.8.0 408 */ 409 public static Duration toDuration(final Object value) throws ConversionException { 410 if (value instanceof Duration) { 411 return (Duration) value; 412 } 413 if (value instanceof CharSequence) { 414 try { 415 return Duration.parse((CharSequence) value); 416 } catch (final DateTimeParseException e) { 417 throw new ConversionException(e, "Could not convert %s to Duration", value); 418 } 419 } 420 throw new ConversionException("The value %s can't be converted to a Duration", value); 421 } 422 423 /** 424 * Converts the specified value into an {@link Enum}. 425 * 426 * @param value the value to convert 427 * @param cls the type of the enumeration 428 * @return the converted value 429 * @throws ConversionException thrown if the value cannot be converted to an enumeration 430 * @since 1.5 431 */ 432 static <E extends Enum<E>> E toEnum(final Object value, final Class<E> cls) throws ConversionException { 433 if (value.getClass().equals(cls)) { 434 return cls.cast(value); 435 } 436 if (value instanceof String) { 437 try { 438 return Enum.valueOf(cls, (String) value); 439 } catch (final Exception e) { 440 throw new ConversionException(e, "The value %s can't be converted to a %s", value, cls.getName()); 441 } 442 } 443 if (!(value instanceof Number)) { 444 throw new ConversionException("The value %s can't be converted to a ", value, cls.getName()); 445 } 446 try { 447 final E[] enumConstants = cls.getEnumConstants(); 448 return enumConstants[((Number) value).intValue()]; 449 } catch (final Exception e) { 450 throw new ConversionException(e, "The value %s can't be converted to a ", value, cls.getName()); 451 } 452 } 453 454 /** 455 * Converts the specified object into a File. 456 * 457 * @param value the value to convert 458 * @return the converted value 459 * @throws ConversionException thrown if the value cannot be converted to a File 460 * @since 2.3 461 */ 462 public static File toFile(final Object value) throws ConversionException { 463 if (value instanceof File) { 464 return (File) value; 465 } 466 if (value instanceof Path) { 467 return ((Path) value).toFile(); 468 } 469 if (value instanceof String) { 470 return new File((String) value); 471 } 472 throw new ConversionException("The value %s can't be converted to a File", value); 473 } 474 475 /** 476 * Converts the specified object into a Float. 477 * 478 * @param value the value to convert 479 * @return the converted value 480 * @throws ConversionException thrown if the value cannot be converted to a Float 481 */ 482 public static Float toFloat(final Object value) throws ConversionException { 483 final Number n = toNumber(value, Float.class); 484 if (n instanceof Float) { 485 return (Float) n; 486 } 487 return Float.valueOf(n.floatValue()); 488 } 489 490 /** 491 * Converts the specified value into an internet address. 492 * 493 * @param value the value to convert 494 * @return the converted value 495 * @throws ConversionException thrown if the value cannot be converted to a InetAddress 496 * @since 1.5 497 */ 498 static InetAddress toInetAddress(final Object value) throws ConversionException { 499 if (value instanceof InetAddress) { 500 return (InetAddress) value; 501 } 502 if (!(value instanceof String)) { 503 throw new ConversionException("The value %s can't be converted to a InetAddress", value); 504 } 505 try { 506 return InetAddress.getByName((String) value); 507 } catch (final UnknownHostException e) { 508 throw new ConversionException(e, "The value %s can't be converted to a InetAddress", value); 509 } 510 } 511 512 /** 513 * Converts the specified object into an Integer. 514 * 515 * @param value the value to convert 516 * @return the converted value 517 * @throws ConversionException thrown if the value cannot be converted to an integer 518 */ 519 public static Integer toInteger(final Object value) throws ConversionException { 520 final Number n = toNumber(value, Integer.class); 521 if (n instanceof Integer) { 522 return (Integer) n; 523 } 524 return n.intValue(); 525 } 526 527 /** 528 * Converts the specified value into an email address with the given class name. 529 * 530 * @param value the value to convert 531 * @param targetClassName the fully qualified name of the {@code InternetAddress} class to convert to, for example, 532 * {@value #INTERNET_ADDRESS_CLASSNAME_JAVAX} or {@value #INTERNET_ADDRESS_CLASSNAME_JAKARTA} 533 * @return the converted value 534 * @throws ConversionException thrown if the value cannot be converted to an email address 535 * @since 1.5 536 */ 537 static Object toInternetAddress(final Object value, final String targetClassName) throws ConversionException { 538 if (value.getClass().getName().equals(targetClassName)) { 539 return value; 540 } 541 if (!(value instanceof String)) { 542 throw new ConversionException("The value %s can't be converted to an InternetAddress", value); 543 } 544 try { 545 final Constructor<?> ctor = Class.forName(targetClassName).getConstructor(String.class); 546 return ctor.newInstance(value); 547 } catch (final Exception e) { 548 throw new ConversionException(e, "The value %s can't be converted to an InternetAddress", value); 549 } 550 } 551 552 /** 553 * Converts the specified object into a Locale. 554 * 555 * @param value the value to convert 556 * @return the converted value 557 * @throws ConversionException thrown if the value cannot be converted to a Locale 558 */ 559 public static Locale toLocale(final Object value) throws ConversionException { 560 if (value instanceof Locale) { 561 return (Locale) value; 562 } 563 if (!(value instanceof String)) { 564 throw new ConversionException("The value %s can't be converted to a Locale", value); 565 } 566 final String[] elements = ((String) value).split("_"); 567 final int size = elements.length; 568 569 if (size >= 1 && (elements[0].length() == 2 || elements[0].isEmpty())) { 570 final String language = elements[0]; 571 final String country = size >= 2 ? elements[1] : ""; 572 final String variant = size >= 3 ? elements[2] : ""; 573 574 return new Locale(language, country, variant); 575 } 576 throw new ConversionException("The value %s can't be converted to a Locale", value); 577 } 578 579 /** 580 * Converts the specified object into a Long. 581 * 582 * @param value the value to convert 583 * @return the converted value 584 * @throws ConversionException thrown if the value cannot be converted to a Long 585 */ 586 public static Long toLong(final Object value) throws ConversionException { 587 final Number n = toNumber(value, Long.class); 588 if (n instanceof Long) { 589 return (Long) n; 590 } 591 return n.longValue(); 592 } 593 594 /** 595 * Tries to convert the specified object into a number object. This method is used by the conversion methods for number 596 * types. Note that the return value is not in always of the specified target class, but only if a new object has to be 597 * created. 598 * 599 * @param value the value to be converted (must not be <strong>null</strong>) 600 * @param targetClass the target class of the conversion (must be derived from {@link Number}) 601 * @return the converted number 602 * @throws ConversionException if the object cannot be converted 603 */ 604 static Number toNumber(final Object value, final Class<?> targetClass) throws ConversionException { 605 if (value instanceof Number) { 606 return (Number) value; 607 } 608 final String str = Objects.toString(value, null); 609 if (Strings.CS.startsWithAny(str, HEX_PREFIX)) { 610 try { 611 return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX); 612 } catch (final NumberFormatException e) { 613 throw new ConversionException(e, "Could not convert %s to %s! Invalid hex number.", str, targetClass.getName()); 614 } 615 } 616 if (Strings.CS.startsWithAny(str, BIN_PREFIX)) { 617 try { 618 return new BigInteger(str.substring(BIN_PREFIX.length()), BIN_RADIX); 619 } catch (final NumberFormatException e) { 620 throw new ConversionException(e, "Could not convert %s to %s! Invalid binary number.", str, targetClass.getName()); 621 } 622 } 623 try { 624 final Constructor<?> constr = targetClass.getConstructor(CONSTR_ARGS); 625 return (Number) constr.newInstance(str); 626 } catch (final InvocationTargetException e) { 627 throw new ConversionException(e.getTargetException(), "Could not convert %s to %s", str, targetClass.getName()); 628 } catch (final Exception e) { 629 // Treat all possible exceptions the same way 630 throw new ConversionException(e, "Conversion error when trying to convert %s to %s", str, targetClass.getName()); 631 } 632 } 633 634 /** 635 * Converts the specified object into a Path. 636 * 637 * @param value the value to convert 638 * @return the converted value 639 * @throws ConversionException thrown if the value cannot be converted to a Path 640 * @since 2.3 641 */ 642 public static Path toPath(final Object value) throws ConversionException { 643 if (value instanceof File) { 644 return ((File) value).toPath(); 645 } 646 if (value instanceof Path) { 647 return (Path) value; 648 } 649 if (value instanceof String) { 650 return Paths.get((String) value); 651 } 652 throw new ConversionException("The value %s can't be converted to a Path", value); 653 } 654 655 /** 656 * Converts the specified object into a Pattern. 657 * 658 * @param value the value to convert 659 * @return the converted value 660 * @throws ConversionException thrown if the value cannot be converted to a Pattern 661 */ 662 public static Pattern toPattern(final Object value) throws ConversionException { 663 if (value instanceof Pattern) { 664 return (Pattern) value; 665 } 666 if (!(value instanceof String)) { 667 throw new ConversionException("The value %s can't be converted to a Pattern", value); 668 } 669 try { 670 return Pattern.compile((String) value); 671 } catch (final PatternSyntaxException e) { 672 throw new ConversionException(e, "The value %s can't be converted to a Pattern", value); 673 } 674 } 675 676 /** 677 * Converts the specified object into a Short. 678 * 679 * @param value the value to convert 680 * @return the converted value 681 * @throws ConversionException thrown if the value cannot be converted to a short 682 */ 683 public static Short toShort(final Object value) throws ConversionException { 684 final Number n = toNumber(value, Short.class); 685 if (n instanceof Short) { 686 return (Short) n; 687 } 688 return n.shortValue(); 689 } 690 691 /** 692 * Converts the specified object into an URI. 693 * 694 * @param value the value to convert 695 * @return the converted value 696 * @throws ConversionException thrown if the value cannot be converted to an URI 697 */ 698 public static URI toURI(final Object value) throws ConversionException { 699 if (value instanceof URI) { 700 return (URI) value; 701 } 702 if (!(value instanceof String)) { 703 throw new ConversionException("The value %s can't be converted to an URI", value); 704 } 705 try { 706 return new URI((String) value); 707 } catch (final URISyntaxException e) { 708 throw new ConversionException(e, "The value %s can't be converted to an URI", value); 709 } 710 } 711 712 /** 713 * Converts the specified object into an URL. 714 * 715 * @param value the value to convert 716 * @return the converted value 717 * @throws ConversionException thrown if the value cannot be converted to an URL 718 */ 719 public static URL toURL(final Object value) throws ConversionException { 720 if (value instanceof URL) { 721 return (URL) value; 722 } 723 if (!(value instanceof String)) { 724 throw new ConversionException("The value %s can't be converted to an URL", value); 725 } 726 try { 727 return new URL((String) value); 728 } catch (final MalformedURLException e) { 729 throw new ConversionException(e, "The value %s can't be converted to an URL", value); 730 } 731 } 732 733 /** 734 * Private constructor prevents instances from being created. 735 */ 736 private PropertyConverter() { 737 // presvents instantiation. 738 } 739}