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