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