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.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; 048 049/** 050 * A utility class to convert the configuration properties into any type. 051 * 052 * @since 2.8.0 053 */ 054public final class PropertyConverter { 055 056 /** Constant for the prefix of hex numbers. */ 057 private static final String HEX_PREFIX = "0x"; 058 059 /** Constant for the radix of hex numbers. */ 060 private static final int HEX_RADIX = 16; 061 062 /** Constant for the prefix of binary numbers. */ 063 private static final String BIN_PREFIX = "0b"; 064 065 /** Constant for the radix of binary numbers. */ 066 private static final int BIN_RADIX = 2; 067 068 /** Constant for the argument classes of the Number constructor that takes a String. */ 069 private static final Class<?>[] CONSTR_ARGS = {String.class}; 070 071 /** The fully qualified name of {@code javax.mail.internet.InternetAddress}, as used in the javamail-1.* API. */ 072 private static final String INTERNET_ADDRESS_CLASSNAME_JAVAX = "javax.mail.internet.InternetAddress"; 073 074 /** The fully qualified name of {@code jakarta.mail.internet.InternetAddress}, as used in the javamail-2.0+ API. */ 075 private static final String INTERNET_ADDRESS_CLASSNAME_JAKARTA = "jakarta.mail.internet.InternetAddress"; 076 077 /** 078 * Converts a value to a constant of an enumeration class. 079 * 080 * @param enumClass the enumeration class 081 * @param value the value to be converted 082 * @return the converted value 083 */ 084 @SuppressWarnings("unchecked") 085 // conversion is safe because we know that the class is an Enum class 086 private static Object convertToEnum(final Class<?> enumClass, final Object value) { 087 return toEnum(value, enumClass.asSubclass(Enum.class)); 088 } 089 090 /** 091 * Converts the specified value object to the given target data class. If additional 092 * information is required for this conversion, it is obtained from the passed in {@code DefaultConversionHandler} 093 * object. If the class is a primitive type (Integer.TYPE, Boolean.TYPE, etc), the value returned will use the wrapper 094 * type (Integer.class, Boolean.class, etc). 095 * 096 * @param cls the target class of the converted value 097 * @param value the value to convert 098 * @param convHandler the conversion handler object 099 * @return the converted value 100 * @throws ConversionException if the value is not compatible with the requested type 101 */ 102 public static Object to(final Class<?> cls, final Object value, final DefaultConversionHandler convHandler) throws ConversionException { 103 if (cls.isInstance(value)) { 104 return value; // no conversion needed 105 } 106 107 if (String.class.equals(cls)) { 108 return String.valueOf(value); 109 } 110 if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) { 111 return toBoolean(value); 112 } 113 if (Character.class.equals(cls) || Character.TYPE.equals(cls)) { 114 return toCharacter(value); 115 } 116 if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) { 117 if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) { 118 return toInteger(value); 119 } 120 if (Long.class.equals(cls) || Long.TYPE.equals(cls)) { 121 return toLong(value); 122 } 123 if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) { 124 return toByte(value); 125 } 126 if (Short.class.equals(cls) || Short.TYPE.equals(cls)) { 127 return toShort(value); 128 } 129 if (Float.class.equals(cls) || Float.TYPE.equals(cls)) { 130 return toFloat(value); 131 } 132 if (Double.class.equals(cls) || Double.TYPE.equals(cls)) { 133 return toDouble(value); 134 } 135 if (BigInteger.class.equals(cls)) { 136 return toBigInteger(value); 137 } 138 if (BigDecimal.class.equals(cls)) { 139 return toBigDecimal(value); 140 } 141 return toNumber(value, cls); 142 } 143 if (Date.class.equals(cls)) { 144 return toDate(value, convHandler.getDateFormat()); 145 } 146 if (Calendar.class.equals(cls)) { 147 return toCalendar(value, convHandler.getDateFormat()); 148 } 149 if (File.class.equals(cls)) { 150 return toFile(value); 151 } 152 if (Path.class.equals(cls)) { 153 return toPath(value); 154 } 155 if (URI.class.equals(cls)) { 156 return toURI(value); 157 } 158 if (URL.class.equals(cls)) { 159 return toURL(value); 160 } 161 if (Pattern.class.equals(cls)) { 162 return toPattern(value); 163 } 164 if (Locale.class.equals(cls)) { 165 return toLocale(value); 166 } 167 if (cls.isEnum()) { 168 return convertToEnum(cls, value); 169 } 170 if (Color.class.equals(cls)) { 171 return toColor(value); 172 } 173 if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAVAX)) { 174 // javamail-1.* With javax.mail.* namespace. 175 return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAVAX); 176 } 177 if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME_JAKARTA)) { 178 // javamail-2.0+, with jakarta.mail.* namespace. 179 return toInternetAddress(value, INTERNET_ADDRESS_CLASSNAME_JAKARTA); 180 } 181 if (InetAddress.class.isAssignableFrom(cls)) { 182 return toInetAddress(value); 183 } 184 if (Duration.class.equals(cls)) { 185 return toDuration(value); 186 } 187 188 throw new ConversionException("The value '" + value + "' (" + value.getClass() + ")" + " can't be converted to a " + cls.getName() + " object"); 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 " + value + " can't be converted to a Boolean object"); 237 } 238 final Boolean b = BooleanUtils.toBooleanObject((String) value); 239 if (b == null) { 240 throw new ConversionException("The value " + value + " can't be converted to a Boolean object"); 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 " + value + " can't be converted to a Calendar"); 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("The value " + value + " can't be converted to a Calendar", e); 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(String.format("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 " + value + " can't be converted to a Color"); 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 " + value + " can't be converted to a Color"); 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("The value " + value + " can't be converted to a Color", e); 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 " + value + " can't be converted to a Date"); 378 } 379 try { 380 return new SimpleDateFormat(format).parse((String) value); 381 } catch (final ParseException e) { 382 throw new ConversionException("The value " + value + " can't be converted to a Date", e); 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("Could not convert " + value + " to Duration", e); 418 } 419 } 420 throw new ConversionException("The value " + value + " can't be converted to a Duration"); 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("The value " + value + " can't be converted to a " + cls.getName()); 441 } 442 } 443 if (!(value instanceof Number)) { 444 throw new ConversionException("The value " + value + " can't be converted to a " + 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("The value " + value + " can't be converted to a " + 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 " + value + " can't be converted to a File"); 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 " + value + " can't be converted to a InetAddress"); 504 } 505 try { 506 return InetAddress.getByName((String) value); 507 } catch (final UnknownHostException e) { 508 throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e); 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 " + value + " can't be converted to an InternetAddress"); 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("The value " + value + " can't be converted to an InternetAddress", e); 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 " + value + " can't be converted to a Locale"); 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 " + value + " can't be converted to a Locale"); 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 (StringUtils.startsWithAny(str, HEX_PREFIX)) { 610 try { 611 return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX); 612 } catch (final NumberFormatException nex) { 613 throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid hex number.", nex); 614 } 615 } 616 617 if (StringUtils.startsWithAny(str, BIN_PREFIX)) { 618 try { 619 return new BigInteger(str.substring(BIN_PREFIX.length()), BIN_RADIX); 620 } catch (final NumberFormatException nex) { 621 throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid binary number.", nex); 622 } 623 } 624 625 try { 626 final Constructor<?> constr = targetClass.getConstructor(CONSTR_ARGS); 627 return (Number) constr.newInstance(str); 628 } catch (final InvocationTargetException itex) { 629 throw new ConversionException("Could not convert " + str + " to " + targetClass.getName(), itex.getTargetException()); 630 } catch (final Exception ex) { 631 // Treat all possible exceptions the same way 632 throw new ConversionException("Conversion error when trying to convert " + str + " to " + targetClass.getName(), ex); 633 } 634 } 635 636 /** 637 * Converts the specified object into a Path. 638 * 639 * @param value the value to convert 640 * @return the converted value 641 * @throws ConversionException thrown if the value cannot be converted to a Path 642 * @since 2.3 643 */ 644 public static Path toPath(final Object value) throws ConversionException { 645 if (value instanceof File) { 646 return ((File) value).toPath(); 647 } 648 if (value instanceof Path) { 649 return (Path) value; 650 } 651 if (value instanceof String) { 652 return Paths.get((String) value); 653 } 654 throw new ConversionException("The value " + value + " can't be converted to a Path"); 655 } 656 657 /** 658 * Converts the specified object into a Pattern. 659 * 660 * @param value the value to convert 661 * @return the converted value 662 * @throws ConversionException thrown if the value cannot be converted to a Pattern 663 */ 664 public static Pattern toPattern(final Object value) throws ConversionException { 665 if (value instanceof Pattern) { 666 return (Pattern) value; 667 } 668 if (!(value instanceof String)) { 669 throw new ConversionException("The value " + value + " can't be converted to a Pattern"); 670 } 671 try { 672 return Pattern.compile((String) value); 673 } catch (final PatternSyntaxException e) { 674 throw new ConversionException("The value " + value + " can't be converted to a Pattern", e); 675 } 676 } 677 678 /** 679 * Converts the specified object into a Short. 680 * 681 * @param value the value to convert 682 * @return the converted value 683 * @throws ConversionException thrown if the value cannot be converted to a short 684 */ 685 public static Short toShort(final Object value) throws ConversionException { 686 final Number n = toNumber(value, Short.class); 687 if (n instanceof Short) { 688 return (Short) n; 689 } 690 return n.shortValue(); 691 } 692 693 /** 694 * Converts the specified object into an URI. 695 * 696 * @param value the value to convert 697 * @return the converted value 698 * @throws ConversionException thrown if the value cannot be converted to an URI 699 */ 700 public static URI toURI(final Object value) throws ConversionException { 701 if (value instanceof URI) { 702 return (URI) value; 703 } 704 if (!(value instanceof String)) { 705 throw new ConversionException("The value " + value + " can't be converted to an URI"); 706 } 707 try { 708 return new URI((String) value); 709 } catch (final URISyntaxException e) { 710 throw new ConversionException("The value " + value + " can't be converted to an URI", e); 711 } 712 } 713 714 /** 715 * Converts the specified object into an URL. 716 * 717 * @param value the value to convert 718 * @return the converted value 719 * @throws ConversionException thrown if the value cannot be converted to an URL 720 */ 721 public static URL toURL(final Object value) throws ConversionException { 722 if (value instanceof URL) { 723 return (URL) value; 724 } 725 if (!(value instanceof String)) { 726 throw new ConversionException("The value " + value + " can't be converted to an URL"); 727 } 728 try { 729 return new URL((String) value); 730 } catch (final MalformedURLException e) { 731 throw new ConversionException("The value " + value + " can't be converted to an URL", e); 732 } 733 } 734 735 /** 736 * Private constructor prevents instances from being created. 737 */ 738 private PropertyConverter() { 739 // presvents instantiation. 740 } 741}